package main

import (
	"context"
	"errors"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/juanatsap/cv-site/internal/config"
	"github.com/juanatsap/cv-site/internal/handlers"
	"github.com/juanatsap/cv-site/internal/middleware"
	"github.com/juanatsap/cv-site/internal/templates"
)

const version = "1.0.0"

func main() {
	// Initialize logger
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	log.Println("🚀 Starting CV Server v" + version)

	// Load configuration
	cfg := config.Load()
	log.Printf("✓ Configuration loaded (env: %s)", os.Getenv("GO_ENV"))

	// Initialize template manager
	templateMgr, err := templates.NewManager(&cfg.Template)
	if err != nil {
		log.Fatalf("❌ Failed to initialize templates: %v", err)
	}

	// Initialize handlers
	cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address())
	healthHandler := handlers.NewHealthHandler(version)

	// Setup router
	mux := http.NewServeMux()

	// Create rate limiter for PDF endpoint
	// Allow 3 PDF generations per minute per IP
	pdfRateLimiter := middleware.NewRateLimiter(3, 1*time.Minute)

	// Routes
	mux.HandleFunc("/", cvHandler.Home)
	mux.HandleFunc("/cv", cvHandler.CVContent)
	mux.HandleFunc("/health", healthHandler.Check)

	// Protected PDF endpoint with origin checking + rate limiting
	protectedPDFHandler := middleware.OriginChecker(
		pdfRateLimiter.Middleware(
			http.HandlerFunc(cvHandler.ExportPDF),
		),
	)
	mux.Handle("/export/pdf", protectedPDFHandler)

	// Static files with cache control
	staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("static")))
	mux.Handle("/static/", cacheControl(staticHandler))

	// Apply middleware chain
	handler := middleware.Recovery(
		middleware.Logger(
			middleware.SecurityHeaders(mux),
		),
	)

	// Create server with timeouts
	server := &http.Server{
		Addr:         ":" + cfg.Server.Port,
		Handler:      handler,
		ReadTimeout:  time.Duration(cfg.Server.ReadTimeout) * time.Second,
		WriteTimeout: time.Duration(cfg.Server.WriteTimeout) * time.Second,
		IdleTimeout:  120 * time.Second,
	}

	// Start server in goroutine
	serverErrors := make(chan error, 1)
	go func() {
		log.Printf("✓ Server listening on http://%s:%s", cfg.Server.Host, cfg.Server.Port)
		log.Printf("📄 English: http://%s:%s/?lang=en", cfg.Server.Host, cfg.Server.Port)
		log.Printf("📄 Spanish: http://%s:%s/?lang=es", cfg.Server.Host, cfg.Server.Port)
		log.Printf("❤️  Health: http://%s:%s/health", cfg.Server.Host, cfg.Server.Port)
		log.Println("Press Ctrl+C to shutdown")

		serverErrors <- server.ListenAndServe()
	}()

	// Setup graceful shutdown
	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)

	// Wait for shutdown signal or server error
	select {
	case err := <-serverErrors:
		if !errors.Is(err, http.ErrServerClosed) {
			log.Fatalf("❌ Server error: %v", err)
		}

	case sig := <-shutdown:
		log.Printf("🛑 Shutdown signal received: %v", sig)

		// Create shutdown context with timeout
		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()

		// Attempt graceful shutdown
		if err := server.Shutdown(ctx); err != nil {
			log.Printf("⚠️  Graceful shutdown failed, forcing: %v", err)
			if err := server.Close(); err != nil {
				log.Fatalf("❌ Failed to close server: %v", err)
			}
		}

		log.Println("✓ Server stopped gracefully")
	}
}

// cacheControl adds cache headers to static files
func cacheControl(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Cache static files for 1 hour in development, 1 day in production
		maxAge := "3600" // 1 hour
		if os.Getenv("GO_ENV") == "production" {
			maxAge = "86400" // 1 day
		}

		w.Header().Set("Cache-Control", "public, max-age="+maxAge)
		h.ServeHTTP(w, r)
	})
}
