package main

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

	"inboxer/src/internal/ai"
	"inboxer/src/internal/auth"
	"inboxer/src/internal/db"
	"inboxer/src/internal/web"
	"inboxer/src/internal/worker"
	"inboxer/src/pkg/config"
	"github.com/gorilla/mux"
)

func main() {
	// Load configuration
	configPath, err := config.GetDefaultConfigPath()
	if err != nil {
		configPath = "bin/config.yaml"
	}

	cfg, env, err := config.LoadConfig(configPath)
	if err != nil {
		log.Fatalf("Failed to load configuration: %v", err)
	}

	// Initialize database
	database, err := db.NewDatabase(cfg.Database.Path, cfg.Server.SessionSecret)
	if err != nil {
		log.Fatalf("Failed to initialize database: %v", err)
	}
	defer database.Close()

	// Initialize SMTP sender
	smtpConfig := auth.SMTPConfig{
		Host:     env.SMTPHost,
		Port:     env.SMTPPort,
		Username: env.SMTPUser,
		Password: env.SMTPPass,
		From:     env.SMTPUser,
	}

	// Validate SMTP config (but don't fail if not set - user might configure later)
	if err := smtpConfig.ValidateConfig(); err != nil {
		log.Printf("Warning: SMTP configuration incomplete: %v", err)
		log.Println("OTP emails will not be sent until SMTP is configured in .env")
	}

	smtpSender := auth.NewSMTPSender(smtpConfig)

	// Initialize session manager
	sessionManager := auth.NewSessionManager(cfg.Server.SessionSecret)
	// In development, allow non-HTTPS
	if os.Getenv("APP_ENV") == "development" {
		sessionManager.UpdateSessionOptions(false, 86400*7)
	}

	// Initialize OTP store (database-backed)
	otpStore := db.NewDatabaseOTPStore(database)

	// Initialize auth service
	authService := auth.NewAuthService(smtpSender, sessionManager, otpStore)

	// Initialize AI classifier
	deepSeekAPI := ai.NewDeepSeekAPI(
		env.DeepSeekAPIKey,
		cfg.AI.Model,
		cfg.AI.MaxTokens,
		cfg.AI.Temperature,
	)
	var classifier worker.AIClassifier
	classifier, err = ai.NewClassifier(deepSeekAPI, cfg.AI.PromptFile)
	if err != nil {
		log.Printf("Warning: AI classifier initialization failed: %v", err)
		log.Println("Falling back to placeholder classifier (all emails -> Other)")
		classifier = worker.NewPlaceholderClassifier(cfg.Folders.Other)
	}

	// Create background worker (not started yet — handlers need a reference first)
	bgWorker := worker.NewWorker(database, cfg, classifier)

	// Initialize web handlers (needs worker for ProcessNow)
	handler, err := web.NewHandler(authService, database, cfg, bgWorker)
	if err != nil {
		log.Fatalf("Failed to initialize web handlers: %v", err)
	}

	// Setup router
	router := mux.NewRouter()
	handler.RegisterRoutes(router)

	// Add middleware
	router.Use(loggingMiddleware)
	router.Use(authMiddleware(authService))

	// Create HTTP server
	server := &http.Server{
		Addr:         fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
		Handler:      router,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	// Start background worker (now that everything is wired up)
	bgWorker.Start()

	// Start server in goroutine
	go func() {
		log.Printf("Starting server on %s", server.Addr)
		log.Printf("Access the application at http://localhost:%d", cfg.Server.Port)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("Server error: %v", err)
		}
	}()

	// Wait for interrupt signal
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop

	log.Println("Shutting down...")

	// Stop background worker first
	bgWorker.Stop()

	// Give server time to shutdown gracefully
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	if err := server.Shutdown(ctx); err != nil {
		log.Printf("Server shutdown error: %v", err)
	}

	log.Println("Server stopped")
}

// loggingMiddleware logs HTTP requests
func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		next.ServeHTTP(w, r)
		log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
	})
}

// authMiddleware checks authentication for protected routes
func authMiddleware(authService *auth.AuthService) mux.MiddlewareFunc {
	protectedPaths := map[string]bool{
		"/dashboard":         true,
		"/settings":          true,
		"/logout":            true,
		"/toggle-test-mode":  true,
		"/test-connection":   true,
		"/process-now":       true,
	}

	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Check if path is protected
			if protectedPaths[r.URL.Path] {
				// Check if user is logged in
				if !authService.GetSessionManager().IsLoggedIn(r) {
					http.Redirect(w, r, "/login", http.StatusSeeOther)
					return
				}
			}
			next.ServeHTTP(w, r)
		})
	}
}