package main

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

	"backend/internal/config"
	"backend/internal/database"
	"backend/internal/handlers"
	"backend/internal/jobs"
	"backend/internal/middleware/auth"
	"backend/internal/services"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
	"github.com/hibiken/asynq"
	"github.com/joho/godotenv"
)

func main() {
	// Load environment variables
	if err := godotenv.Load(); err != nil {
		log.Println("No .env file found, using environment variables")
	}

	// Load configuration
	cfg := config.Load()

	// Initialize database
	db, err := database.NewConnection(cfg.DatabaseURL)
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer db.Close()

	// Initialize email service for worker
	emailService := services.NewEmailService(
		cfg.SMTPHost,
		cfg.SMTPPort,
		cfg.SMTPUsername,
		cfg.SMTPPassword,
		cfg.SMTPFromEmail,
		cfg.SMTPFromName,
	)

	// Initialize queue client
	queueClient, err := jobs.NewQueueClient(cfg.RedisAddr, cfg.RedisPassword, cfg.RedisDB)
	if err != nil {
		log.Fatalf("Failed to connect to Redis queue: %v", err)
	}
	defer queueClient.Close()

	// Initialize queue server and worker
	queueServer := jobs.NewQueueServer(cfg.RedisAddr, cfg.RedisPassword, cfg.RedisDB)

	// Register email job handlers
	mux := asynq.NewServeMux()
	mux.HandleFunc(jobs.TypeSendOTPEmail, jobs.ProcessSendOTPEmail(emailService))

	// Start worker in background
	go func() {
		if err := queueServer.Run(mux); err != nil {
			log.Fatalf("Queue worker failed: %v", err)
		}
	}()
	log.Println("Queue worker started")

	// Initialize handlers
	h := handlers.New(
		db,
		cfg.JWTSecret,
		cfg.JWTExpiry,
		queueClient,
	)

	// Set auth service in middleware
	auth.SetAuthService(h.GetAuthService())

	// Setup router
	r := chi.NewRouter()

	// Middleware
	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	// CORS configuration - must be before routes
	// The go-chi/cors middleware automatically handles OPTIONS preflight requests
	allowedOrigins := []string{
		"http://localhost:5173",
		"http://localhost:8081",
		"http://localhost:3000",
		"https://client-net.taifaguard.co.ke",
		"https://www.client-net.taifaguard.co.ke",
		"https://demo.taifaguard.co.ke", // API domain itself (for same-origin requests)
	}

	r.Use(cors.Handler(cors.Options{
		AllowedOrigins:   allowedOrigins,
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"},
		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token", "X-Requested-With", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"},
		ExposedHeaders:   []string{"Link", "Content-Length", "Content-Type"},
		AllowCredentials: true,
		MaxAge:           86400, // 24 hours - cache preflight for 24 hours
		Debug:            false,
	}))

	// Additional CORS logging middleware for debugging
	r.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			origin := r.Header.Get("Origin")
			if origin != "" {
				log.Printf("CORS request from origin: %s, method: %s, path: %s", origin, r.Method, r.URL.Path)
			}
			next.ServeHTTP(w, r)
		})
	})

	// Health check
	r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	// Auth routes (public)
	r.Route("/api/v1/auth", func(r chi.Router) {
		r.Post("/login", h.Login)
		r.Post("/logout", h.Logout)
		r.Post("/forgot-password", h.ForgotPassword)
		r.Post("/verify-otp", h.VerifyOTP)
		r.Post("/reset-password", h.ResetPassword)
		r.Get("/me", auth.RequireAuth(h.GetCurrentUser))
	})

	// Package routes (protected - require authentication)
	r.Route("/api/v1/packages", func(r chi.Router) {
		r.Use(func(next http.Handler) http.Handler {
			return auth.RequireAuth(next.ServeHTTP)
		})
		r.Post("/", h.CreatePackage)
		r.Get("/", h.GetAllPackages)
		r.Get("/{id}", h.GetPackage)
		r.Put("/{id}", h.UpdatePackage)
		r.Delete("/{id}", h.DeletePackage)
	})

	// Transaction routes (protected - require authentication)
	r.Route("/api/v1/transactions", func(r chi.Router) {
		r.Use(func(next http.Handler) http.Handler {
			return auth.RequireAuth(next.ServeHTTP)
		})
		r.Get("/", h.GetAllTransactions)
		r.Get("/{id}", h.GetTransaction)
	})

	// Start server
	addr := fmt.Sprintf("%s:%s", cfg.Host, cfg.Port)
	log.Printf("Server starting on %s", addr)

	// Graceful shutdown
	server := &http.Server{
		Addr:    addr,
		Handler: r,
	}

	// Start server in goroutine
	go func() {
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("Server failed to start: %v", err)
		}
	}()

	// Wait for interrupt signal to gracefully shutdown
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

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

	// Shutdown queue server
	queueServer.Shutdown()

	// Shutdown HTTP server
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	if err := server.Shutdown(ctx); err != nil {
		log.Fatalf("Server forced to shutdown: %v", err)
	}

	log.Println("Server exited")
}
