package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"

	"github.com/pulse-lets-go/internal/config"
	"github.com/pulse-lets-go/internal/engine"
	"github.com/pulse-lets-go/internal/esl"
	"github.com/pulse-lets-go/internal/models"
)

// API — главная структура HTTP API, агрегирует все зависимости.
type API struct {
	engine           *engine.Engine
	configManager    *config.Manager
	jwtSecret        string
	monitoringAPIKey string
	wsHub            *wsHub
	natsConnected    func() bool // колбэк для проверки NATS-статуса (health)
	eslClient        *esl.Client // ESL-клиент (nil если не сконфигурирован)
	logFormat        string
	routeLimiter     *rateLimiter
	apiLimiter       *rateLimiter

	// In-memory кэш gateway для /api/route (устраняет disk I/O в hot path)
	trunkCacheMu    sync.RWMutex
	balanceGateways map[string]string // nodeID → gateway
	fallbackGateway string

	gatewayMu     sync.RWMutex
	gatewayStates map[string]string // trunkID → "up"/"down"
	fsStats       esl.FsStats
	fsStatsMu     sync.RWMutex

	routeCachePath string // путь к файловому кэшу маршрута (для Lua)
}

// NewAPI создаёт новый HTTP API с заданными зависимостями.
func NewAPI(eng *engine.Engine, cfgMgr *config.Manager, jwtSecret, monitoringAPIKey string, natsFn func() bool, cfg *config.Config) *API {
	a := &API{
		engine:           eng,
		configManager:    cfgMgr,
		jwtSecret:        jwtSecret,
		monitoringAPIKey: monitoringAPIKey,
		wsHub:            newWSHub(),
		natsConnected:    natsFn,
		logFormat:        cfg.Log.Format,
		gatewayStates:    make(map[string]string),
		balanceGateways:  make(map[string]string),
	}
	if cfg.RateLimit.Enabled {
		a.routeLimiter = newRateLimiter(cfg.RateLimit.RoutePerSec, cfg.RateLimit.RoutePerSec)
		a.apiLimiter = newRateLimiter(cfg.RateLimit.APIPerSec, cfg.RateLimit.APIPerSec)
	}
	return a
}

// SetESLClient устанавливает ESL-клиент (вызывается после инициализации ESL).
func (a *API) SetESLClient(client *esl.Client) {
	a.eslClient = client
}

// Handler возвращает http.Handler со всеми зарегистрированными маршрутами.
func (a *API) Handler() http.Handler {
	mux := http.NewServeMux()

	// --- Health endpoints (без авторизации) ---

	mux.HandleFunc("GET /api/health", a.handleHealth)
	mux.HandleFunc("GET /api/health/live", a.handleLiveness)
	mux.HandleFunc("GET /api/health/ready", a.handleReadiness)

	// --- Публичные маршруты (без авторизации) ---

	mux.HandleFunc("POST /api/auth/login", a.handleLogin)
	mux.HandleFunc("POST /api/auth/refresh", a.handleRefresh)
	mux.HandleFunc("GET /api/route", a.handleRoute)
	mux.HandleFunc("GET /ws/metrics", a.handleWS)

	// Monitoring с API-key (без JWT)
	mux.Handle("GET /api/monitoring/zabbix", a.apiKeyMiddleware(http.HandlerFunc(a.handleZabbix)))
	mux.Handle("GET /api/monitoring/prometheus", a.apiKeyMiddleware(http.HandlerFunc(a.handlePrometheus)))

	// --- Админка: Nodes (admin + viewer) ---

	mux.Handle("GET /api/nodes", a.authMiddleware(http.HandlerFunc(a.handleGetNodes)))
	mux.Handle("GET /api/nodes/{id}/metrics", a.authMiddleware(http.HandlerFunc(a.handleGetNodeMetrics)))
	mux.Handle("PUT /api/nodes/{id}/toggle", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleToggleNode))))
	mux.Handle("PUT /api/route/mode", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleSetRouteMode))))

	// --- Админка: Trunks (admin only) ---

	mux.Handle("GET /api/trunks", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleGetTrunks))))
	mux.Handle("POST /api/trunks", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleCreateTrunk))))
	mux.Handle("PUT /api/trunks/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleUpdateTrunk))))
	mux.Handle("DELETE /api/trunks/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleDeleteTrunk))))

	// --- Админка: Users (admin only) ---

	mux.Handle("GET /api/users", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleGetUsers))))
	mux.Handle("POST /api/users", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleCreateUser))))
	mux.Handle("PUT /api/users/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleUpdateUser))))
	mux.Handle("DELETE /api/users/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleDeleteUser))))

	// --- Админка: Routing Rules (admin + viewer for GET, admin only for write) ---

	mux.Handle("GET /api/routing/rules", a.authMiddleware(http.HandlerFunc(a.handleGetRoutingRules)))
	mux.Handle("POST /api/routing/rules", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleCreateRoutingRule))))
	mux.Handle("PUT /api/routing/rules/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleUpdateRoutingRule))))
	mux.Handle("DELETE /api/routing/rules/{id}", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleDeleteRoutingRule))))
	mux.Handle("PUT /api/routing/rules/{id}/toggle", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleToggleRoutingRule))))
	mux.Handle("PUT /api/routing/rules/reorder", a.authMiddleware(a.adminOnly(http.HandlerFunc(a.handleReorderRoutingRules))))

	// Логирование + CORS (навешиваем после mux)
	var wrapped http.Handler = mux
	wrapped = requestLoggingMiddleware(a.logFormat)(wrapped)

	// Rate limiting
	if a.routeLimiter != nil && a.apiLimiter != nil {
		handlerBeforeRL := wrapped
		wrapped = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path == "/api/route" {
				rateLimitMiddleware(a.routeLimiter)(handlerBeforeRL).ServeHTTP(w, r)
				return
			}
			if len(r.URL.Path) > 5 && r.URL.Path[:5] == "/api/" {
				rateLimitMiddleware(a.apiLimiter)(handlerBeforeRL).ServeHTTP(w, r)
				return
			}
			handlerBeforeRL.ServeHTTP(w, r)
		})
	}

	return corsMiddleware(wrapped)
}

// corsMiddleware добавляет CORS-заголовки.
func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key")

		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		next.ServeHTTP(w, r)
	})
}

// BroadcastGatewayEvent транслирует статус gateway всем WS-клиентам.
func (a *API) BroadcastGatewayEvent(gatewayName, trunkID, status string) {
	a.gatewayMu.Lock()
	a.gatewayStates[trunkID] = status
	a.gatewayMu.Unlock()

	msg := &models.WsMetricsMessage{
		Type: "gateway_update",
		Payload: map[string]string{
			"gateway":  gatewayName,
			"trunk_id": trunkID,
			"status":   status,
		},
	}
	a.wsHub.broadcast(msg)
}

func (a *API) gatewayStats() (total, up, down int) {
	a.gatewayMu.RLock()
	defer a.gatewayMu.RUnlock()
	for _, s := range a.gatewayStates {
		total++
		switch s {
		case "up":
			up++
		case "down":
			down++
		}
	}
	return
}

// RebuildTrunkCache перестраивает in-memory кэш gateway для /api/route.
// Вызывается при старте и после любого CRUD-оперирования с транками.
func (a *API) RebuildTrunkCache() {
	trunks, err := a.configManager.ReadTrunks()
	if err != nil {
		return
	}

	a.trunkCacheMu.Lock()
	defer a.trunkCacheMu.Unlock()

	a.balanceGateways = make(map[string]string, len(trunks))
	a.fallbackGateway = ""

	for _, t := range trunks {
		if t.Enabled {
			switch t.Type {
			case models.TrunkBalance:
				if t.NodeID != "" {
					a.balanceGateways[t.NodeID] = t.Gateway
				}
			case models.TrunkFallback:
				if a.fallbackGateway == "" {
					a.fallbackGateway = t.Gateway
				}
			}
		}
	}
}

// UpdateFsStats обновляет кэш метрик FreeSWITCH (вызывается из ticker).
func (a *API) UpdateFsStats(stats esl.FsStats) {
	a.fsStatsMu.Lock()
	a.fsStats = stats
	a.fsStatsMu.Unlock()
}

// maxBodySize — максимальный размер тела запроса в байтах (1 MiB).
const maxBodySize = 1 << 20

// decodeJSON декодирует тело запроса в структуру v с ограничением размера.
func decodeJSON(r *http.Request, v interface{}) error {
	defer r.Body.Close()
	r.Body = http.MaxBytesReader(nil, r.Body, maxBodySize)
	if err := json.NewDecoder(r.Body).Decode(v); err != nil {
		return fmt.Errorf("декодирование JSON: %w", err)
	}
	return nil
}
