package metrics

import (
	"net/http"
	"sync"

	"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
	"github.com/prometheus/client_golang/prometheus"
	dto "github.com/prometheus/client_model/go"
	"go.uber.org/zap"
)

type AppMetrics struct {
	logger  *zap.Logger
	gate    *GateMetrics
	mu      sync.RWMutex
	enabled bool
}

type AppMetricsConfig struct {
	Logger         *zap.Logger
	PoolStatistics StatisticScraper
	TreeStatistic  TreePoolStatistic
	Registerer     prometheus.Registerer
	Enabled        bool
}

func NewAppMetrics(cfg AppMetricsConfig) *AppMetrics {
	if !cfg.Enabled {
		cfg.Logger.Warn(logs.MetricsAreDisabled)
	}

	registry := cfg.Registerer
	if registry == nil {
		registry = prometheus.DefaultRegisterer
	}

	return &AppMetrics{
		logger:  cfg.Logger,
		gate:    NewGateMetrics(cfg.PoolStatistics, cfg.TreeStatistic, registry),
		enabled: cfg.Enabled,
	}
}

func (m *AppMetrics) SetEnabled(enabled bool) {
	if !enabled {
		m.logger.Warn(logs.MetricsAreDisabled)
	}

	m.mu.Lock()
	m.enabled = enabled
	m.mu.Unlock()
}

func (m *AppMetrics) State() *StateMetrics {
	if !m.isEnabled() {
		return nil
	}

	return m.gate.State
}

func (m *AppMetrics) Shutdown() {
	m.mu.Lock()
	if m.enabled {
		m.gate.State.SetHealth(HealthStatusShuttingDown)
		m.enabled = false
	}
	m.gate.Unregister()
	m.mu.Unlock()
}

func (m *AppMetrics) isEnabled() bool {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.enabled
}

func (m *AppMetrics) Handler() http.Handler {
	return m.gate.Handler()
}

func (m *AppMetrics) UsersAPIStats() *UsersAPIStats {
	if !m.isEnabled() {
		return nil
	}
	return m.gate.Billing.apiStat
}

func (m *AppMetrics) Statistic() *APIStatMetrics {
	if !m.isEnabled() {
		return nil
	}

	return m.gate.Stats
}

func (m *AppMetrics) Gather() ([]*dto.MetricFamily, error) {
	return m.gate.Gather()
}

func (m *AppMetrics) MarkHealthy(endpoint string) {
	if !m.isEnabled() {
		return
	}

	m.gate.HTTPServer.MarkHealthy(endpoint)
}

func (m *AppMetrics) MarkUnhealthy(endpoint string) {
	if !m.isEnabled() {
		return
	}

	m.gate.HTTPServer.MarkUnhealthy(endpoint)
}