package handlers

import (
	"context"
	"encoding/json"
	"net/http"
	"sync"
	"time"

	"crowdsec-dashy/internal/crowdsec"
)

// APIHandler serves the internal JSON API consumed by frontend JS.
type APIHandler struct {
	deps Deps
}

func NewAPIHandler(deps Deps) *APIHandler {
	return &APIHandler{deps: deps}
}

type statsResponse struct {
	Decisions int  `json:"decisions"`
	Alerts24h int  `json:"alerts_24h"`
	Alerts7d  int  `json:"alerts_7d"`
	Bouncers  int  `json:"bouncers"`
	Machines  int  `json:"machines"`
	Healthy   bool `json:"healthy"`
}

type healthResponse struct {
	Healthy      bool `json:"healthy"`
	CLIAvailable bool `json:"cli_available"`
}

// Stats returns dashboard summary counts.
func (h *APIHandler) Stats(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
	defer cancel()

	// Fetch 24h and 7d alert counts in parallel to minimize latency.
	var alerts24h, alerts7d []crowdsec.Alert
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		alerts24h, _ = h.deps.LAPI.ListAlerts(ctx, crowdsec.AlertFilter{Limit: 5000, Since: "24h"})
	}()
	go func() {
		defer wg.Done()
		alerts7d, _ = h.deps.LAPI.ListAlerts(ctx, crowdsec.AlertFilter{Limit: 5000, Since: "168h"})
	}()
	wg.Wait()

	resp := statsResponse{
		Alerts24h: len(alerts24h),
		Alerts7d:  len(alerts7d),
		Healthy:   h.deps.LAPI.IsHealthy(ctx),
	}

	if h.deps.CLIAvailable {
		decisions, _ := h.deps.CLI.ListDecisions(ctx, crowdsec.DecisionFilter{Limit: 500})
		bouncers, _ := h.deps.CLI.ListBouncers(ctx)
		machines, _ := h.deps.CLI.ListMachines(ctx)
		resp.Decisions = len(decisions)
		resp.Bouncers = len(bouncers)
		resp.Machines = len(machines)
	}

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		http.Error(w, "internal error", http.StatusInternalServerError)
	}
}

// Health returns LAPI health and cscli availability.
func (h *APIHandler) Health(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(healthResponse{
		Healthy:      h.deps.LAPI.IsHealthy(ctx),
		CLIAvailable: h.deps.CLIAvailable,
	}); err != nil {
		http.Error(w, "internal error", http.StatusInternalServerError)
	}
}
