package authguard

import (
	"log/slog"
	"net/http"
	"strconv"
	"strings"

	"github.com/niels/banking-app/backend/internal/audit"
	"github.com/niels/banking-app/backend/internal/domain"
	"github.com/niels/banking-app/backend/internal/httpapi/middleware"
	"github.com/niels/banking-app/backend/internal/platform/httputil"
	"github.com/niels/banking-app/backend/internal/respond"
)

type Handler struct {
	repo  *Repository
	audit *audit.Repository
	log   *slog.Logger
}

func NewHandler(repo *Repository, auditRepo *audit.Repository, log *slog.Logger) *Handler {
	return &Handler{repo: repo, audit: auditRepo, log: log}
}

func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
	dashboard, err := h.repo.Dashboard(
		r.Context(),
		strings.TrimSpace(r.URL.Query().Get("status")),
		queryLimit(r),
	)
	if err != nil {
		respond.Error(w, err)
		return
	}
	respond.JSON(w, http.StatusOK, dashboard)
}

func (h *Handler) Events(w http.ResponseWriter, r *http.Request) {
	events, err := h.repo.ListEvents(
		r.Context(),
		strings.TrimSpace(r.URL.Query().Get("status")),
		queryLimit(r),
	)
	if err != nil {
		respond.Error(w, err)
		return
	}
	respond.JSON(w, http.StatusOK, map[string]any{"events": events})
}

func (h *Handler) DecideEvent(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.CurrentClaims(r)
	if !ok {
		respond.Error(w, domain.ErrUnauthorized)
		return
	}
	eventID := r.PathValue("id")
	if err := domain.ValidateUUID("id", eventID); err != nil {
		respond.Error(w, err)
		return
	}
	var req struct {
		Status         string `json:"status"`
		ResolutionNote string `json:"resolution_note"`
	}
	if err := respond.DecodeJSON(r, &req); err != nil {
		respond.Error(w, err)
		return
	}

	event, err := h.repo.DecideEvent(r.Context(), EventDecisionParams{
		EventID:        eventID,
		AdminUserID:    claims.Subject,
		Status:         req.Status,
		ResolutionNote: req.ResolutionNote,
	})
	if err != nil {
		respond.Error(w, err)
		return
	}
	h.recordAudit(r, claims.Subject, "admin.security_event.updated", event)
	respond.JSON(w, http.StatusOK, event)
}

func (h *Handler) recordAudit(r *http.Request, adminUserID, eventType string, event SecurityEvent) {
	if h.audit == nil {
		return
	}
	if err := h.audit.Record(r.Context(), audit.Event{
		ActorUserID: &adminUserID,
		EventType:   eventType,
		TargetType:  "security_event",
		TargetID:    event.ID,
		Metadata: map[string]any{
			"user_id":    event.UserID,
			"event_type": event.EventType,
			"severity":   event.Severity,
			"status":     event.Status,
			"remote_ip":  event.RemoteIP,
		},
		RemoteIP:  httputil.RemoteIP(r),
		UserAgent: r.UserAgent(),
	}); err != nil && h.log != nil {
		h.log.Error("audit record failed", "error", err)
	}
}

func queryLimit(r *http.Request) int {
	limit := 50
	if raw := r.URL.Query().Get("limit"); raw != "" {
		if parsed, err := strconv.Atoi(raw); err == nil {
			limit = parsed
		}
	}
	return limit
}
