package main

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

	"github.com/go-chi/chi/v5"
	chiMiddleware "github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
	"github.com/joho/godotenv"
	"github.com/zs/InsightReply/internal/handler"
	appMiddleware "github.com/zs/InsightReply/internal/middleware"
	"github.com/zs/InsightReply/internal/repository"
	"github.com/zs/InsightReply/internal/service"
	"github.com/zs/InsightReply/internal/worker"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

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

	// 1.5 Setup application file logging
	if logPath := os.Getenv("LOG_FILE_PATH"); logPath != "" {
		logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err == nil {
			multiWriter := io.MultiWriter(os.Stdout, logFile)
			log.SetOutput(multiWriter)
			log.Printf("Application logs are now being mirrored to: %s", logPath)
		} else {
			log.Printf("Failed to open log file %s: %v", logPath, err)
		}
	}

	// 2. Database connection setup
	dsn := os.Getenv("DATABASE_URL")
	if dsn == "" {
		log.Fatal("DATABASE_URL environment variable is required")
	}

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("failed to connect database:", err)
	}
	fmt.Println("Database connection established")

	// 3. Initialize Layers
	userRepo := repository.NewUserRepository(db)
	userSvc := service.NewUserService(userRepo)
	userHandler := handler.NewUserHandler(userSvc)

	authSvc := service.NewAuthService(userRepo)
	authHandler := handler.NewAuthHandler(authSvc)

	profileRepo := repository.NewProductProfileRepository(db)
	profileSvc := service.NewProductProfileService(profileRepo)
	profileHandler := handler.NewProductProfileHandler(profileSvc)

	strategyRepo := repository.NewCustomStrategyRepository(db)
	strategySvc := service.NewCustomStrategyService(strategyRepo)
	strategyHandler := handler.NewCustomStrategyHandler(strategySvc)

	monitorRepo := repository.NewCompetitorMonitorRepository(db)
	monitorSvc := service.NewCompetitorMonitorService(monitorRepo)
	monitorHandler := handler.NewCompetitorMonitorHandler(monitorSvc)

	// AI Service (Multi-LLM Routing Support)
	aiSvc := service.NewAIService()
	aiHandler := handler.NewAIHandler(aiSvc, profileSvc, strategySvc)

	// Start Background Workers & Tweet Handling
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // Ensure cleanup on exit
	tweetRepo := repository.NewTweetRepository(db)
	replyRepo := repository.NewReplyRepository(db)
	
	tweetHandler := handler.NewTweetHandler(tweetRepo) // Mount API handler
	replyHandler := handler.NewReplyHandler(replyRepo) 

	monitorWorker := worker.NewMonitorWorker(monitorRepo, tweetRepo)
	go monitorWorker.Start(ctx, 15*time.Minute)

	performanceWorker := worker.NewPerformanceWorker(replyRepo, aiSvc)
	go performanceWorker.Start(ctx, 30*time.Minute) // Runs every 30 minutes to check 24h+ old replies

	// 4. Router setup
	r := chi.NewRouter()
	r.Use(chiMiddleware.Logger)
	r.Use(chiMiddleware.Recoverer)
	r.Use(chiMiddleware.StripSlashes)

	// CORS Configuration
	corsOrigins := os.Getenv("CORS_ORIGINS")
	if corsOrigins == "" {
		corsOrigins = "*" // default fallback
	}
	r.Use(cors.Handler(cors.Options{
		AllowedOrigins:   []string{corsOrigins},
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
		ExposedHeaders:   []string{"Link"},
		AllowCredentials: true,
		MaxAge:           300,
	}))

	// 5. Routes
	r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"code":200,"message":"ok","data":{"status":"healthy","version":"1.0.0"}}`))
	})

	r.Route("/api/v1", func(r chi.Router) {
		// Public routes
		r.Post("/users/register", userHandler.Register)
		r.Post("/auth/login", authHandler.Login)

		// Protected routes
		r.Group(func(r chi.Router) {
			r.Use(appMiddleware.JWTAuth)
			r.Use(appMiddleware.RateLimit(db))

			// User and Profile APIs
			r.Get("/users/me", userHandler.GetProfile)
			r.Put("/users/me/preferences", userHandler.UpdatePreferences)
			r.Get("/users/me/product_profiles", profileHandler.GetProfile)
			r.Put("/users/me/product_profiles", profileHandler.SaveProfile)

			// Strategy APIs
			r.Get("/users/me/strategies", strategyHandler.ListStrategies)
			r.Post("/users/me/strategies", strategyHandler.CreateStrategy)
			r.Delete("/users/me/strategies/{id}", strategyHandler.DeleteStrategy)

			// Monitor APIs
			r.Get("/monitors/competitors", monitorHandler.ListMonitors)
			r.Post("/monitors/competitors", monitorHandler.CreateMonitor)
			r.Delete("/monitors/competitors/{id}", monitorHandler.DeleteMonitor)

			// Hot Opportunity Tweers API
			r.Get("/tweets/hot", tweetHandler.GetHotTweets)
			r.Get("/tweets/search", tweetHandler.GetSearchTweets)

			// AI APIs
			r.Get("/ai/test", aiHandler.Test)
			r.Post("/ai/generate", aiHandler.Generate)
			r.Post("/replies/record", replyHandler.RecordReply)
			r.Get("/replies", replyHandler.GetReplies)
		})
	})

	// 6. Graceful Shutdown Setup
	port := os.Getenv("SERVER_PORT")
	if port == "" {
		port = "8080"
	}
	srv := &http.Server{
		Addr:    ":" + port,
		Handler: r,
	}

	serverErrors := make(chan error, 1)

	// Start the server
	go func() {
		fmt.Printf("Server starting on :%s\n", port)
		serverErrors <- srv.ListenAndServe()
	}()

	// Channel to listen for an interrupt or terminate signal from the OS.
	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)

	// Blocking main and waiting for shutdown.
	select {
	case err := <-serverErrors:
		log.Fatalf("Error starting server: %v", err)
	case sig := <-shutdown:
		log.Printf("Start shutdown... signal: %v", sig)

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

		if err := srv.Shutdown(ctx); err != nil {
			log.Printf("Graceful shutdown did not complete in time: %v", err)
			if err := srv.Close(); err != nil {
				log.Fatalf("Could not stop server gracefully: %v", err)
			}
		}
	}
	log.Println("Server stopped")
}
