package gateway

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/acp/interceptor/internal/audit"
	"github.com/acp/interceptor/internal/auth"
	"github.com/acp/interceptor/internal/config"
	"github.com/acp/interceptor/internal/handlers"
	"github.com/acp/interceptor/internal/policy"
	"github.com/acp/interceptor/internal/services"
)

// Server is the HTTP server for the interceptor.
type Server struct {
	cfg     config.Config
	router  *http.Server
	cleanup func()
}

// NewServer constructs dependencies and an HTTP server.
func NewServer(cfg config.Config) (*Server, error) {
	stores, cleanup, err := initPlatformStores(cfg)
	if err != nil {
		return nil, err
	}

	opaClient, err := policy.NewOPAClient(cfg)
	if err != nil {
		cleanup()
		return nil, err
	}
	eval := policy.NewOPAEvaluator(opaClient)
	pol := services.NewPolicyService(eval)

	auditLog := audit.NewLogger(stores.events)
	auditSvc := services.NewAuditService(auditLog)
	interceptor := services.NewInterceptorService(
		pol, auditSvc, stores.approvals, stores.agents, cfg.AgentRegistryEnforce,
	)
	tool := handlers.NewToolHandler(interceptor)
	insights := handlers.NewInsightsHandler(stores.events)
	catalog := handlers.NewPolicyCatalogHandler(cfg.PoliciesDir)
	approvalHandler := handlers.NewApprovalHandler(stores.approvals, stores.events, auditSvc)
	agentHandler := handlers.NewAgentHandler(stores.agents)

	jwtValidator, err := auth.ValidatorFromConfig(cfg)
	if err != nil {
		cleanup()
		return nil, err
	}

	engine := NewRouter(cfg, tool, insights, catalog, approvalHandler, agentHandler, jwtValidator)
	srv := &http.Server{
		Addr:              cfg.HTTPAddr,
		Handler:           engine,
		ReadHeaderTimeout: 5 * time.Second,
		ReadTimeout:       15 * time.Second,
		WriteTimeout:      30 * time.Second,
		IdleTimeout:       60 * time.Second,
	}
	return &Server{cfg: cfg, router: srv, cleanup: cleanup}, nil
}

// Run starts serving until the server is stopped.
func (s *Server) Run() error {
	return s.router.ListenAndServe()
}

// Shutdown gracefully stops the server.
func (s *Server) Shutdown(ctx context.Context) error {
	defer s.cleanup()
	return s.router.Shutdown(ctx)
}

// Addr returns the configured listen address.
func (s *Server) Addr() string {
	return s.cfg.HTTPAddr
}

// String for debugging.
func (s *Server) String() string {
	return fmt.Sprintf("interceptor(%s)", s.cfg.HTTPAddr)
}
