package main

import (
	"log/slog"
	"net/http"
	_ "net/http/pprof"
	"os"
	"time"

	"github.com/lowcarbdev/sbv/internal"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
)

var logger *slog.Logger

func main() {
	// Initialize slog logger
	logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
	}))
	slog.SetDefault(logger)

	// Initialize authentication database
	dbPathPrefix := os.Getenv("DB_PATH_PREFIX")
	if dbPathPrefix == "" {
		dbPathPrefix = "."
	}
	authDBPath := dbPathPrefix + "/sbv.db"

	err := internal.InitAuthDB(authDBPath)
	if err != nil {
		logger.Error("Failed to initialize authentication database", "error", err)
		os.Exit(1)
	}
	logger.Info("Authentication database initialized", "path", authDBPath)

	// Create Echo instance
	e := echo.New()

	// Middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// Use custom CORS middleware that properly handles credentials
	e.Use(internal.CustomCORSMiddleware())

	// Configure timeouts for large file uploads
	e.Server.ReadTimeout = 30 * time.Minute
	e.Server.WriteTimeout = 30 * time.Minute
	e.Server.ReadHeaderTimeout = 1 * time.Minute
	e.Server.IdleTimeout = 2 * time.Minute
	e.Server.MaxHeaderBytes = 1 << 20 // 1 MB max header size

	// Public routes (no authentication required)
	// Apply NoCacheMiddleware to prevent browser caching of auth responses
	e.POST("/api/auth/register", internal.HandleRegister, internal.NoCacheMiddleware)
	e.POST("/api/auth/login", internal.HandleLogin, internal.NoCacheMiddleware)
	e.POST("/api/auth/logout", internal.HandleLogout, internal.NoCacheMiddleware)

	// Protected routes (authentication required)
	protected := e.Group("/api")
	protected.Use(internal.AuthMiddleware)
	protected.Use(internal.NoCacheMiddleware) // Prevent browser caching of API responses

	protected.GET("/auth/me", internal.HandleMe)
	protected.POST("/auth/change-password", internal.HandleChangePassword)
	protected.POST("/upload", internal.HandleUpload)
	protected.GET("/conversations", internal.HandleConversations)
	protected.GET("/messages", internal.HandleMessages)
	protected.GET("/activity", internal.HandleActivity)
	protected.GET("/daterange", internal.HandleDateRange)
	protected.GET("/progress", internal.HandleProgress)
	protected.GET("/media", internal.HandleMedia)
	protected.GET("/search", internal.HandleSearch)

	// Health check
	e.GET("/api/health", func(c echo.Context) error {
		return c.String(http.StatusOK, "OK")
	})

	// Serve static files from frontend/dist if it exists (for production/Docker)
	if _, err := os.Stat("./frontend/dist"); err == nil {
		// Serve static assets (JS, CSS, images, etc.)
		e.Static("/assets", "./frontend/dist/assets")
		e.File("/favicon.ico", "./frontend/dist/favicon.ico")
		e.File("/favicon.svg", "./frontend/dist/favicon.svg")
		e.File("/apple-touch-icon.png", "./frontend/dist/apple-touch-icon.png")
		e.File("/favicon-96x96.png", "./frontend/dist/favicon-96x96.png")
		e.File("/web-app-manifest-192x192.png", "./frontend/dist/web-app-manifest-192x192.png")
		e.File("/web-app-manifest-512x512.png", "./frontend/dist/web-app-manifest-512x512.png")
		e.File("/site.webmanifest", "./frontend/dist/site.webmanifest")

		// SPA fallback - serve index.html for all non-API routes
		// This must be last so it doesn't interfere with API routes
		e.GET("/*", func(c echo.Context) error {
			return c.File("./frontend/dist/index.html")
		})

		logger.Info("Serving static files from ./frontend/dist with SPA routing support")
	}

	// Start pprof server in a separate goroutine for profiling
	go func() {
		port := os.Getenv("PORT")
		if port == "" {
			port = "8081"
		}
		pprofPort := "6060"
		logger.Info("Memory profiling available", "url", "http://localhost:"+pprofPort+"/debug/pprof/")
		if err := http.ListenAndServe(":"+pprofPort, nil); err != nil {
			logger.Error("pprof server failed", "error", err)
		}
	}()

	port := os.Getenv("PORT")
	if port == "" {
		port = "8081"
	}

	// Create HTTP server with longer timeouts for large file uploads
	server := &http.Server{
		Addr:              ":" + port,
		ReadTimeout:       30 * time.Minute, // Allow 30 minutes for reading large uploads
		WriteTimeout:      30 * time.Minute, // Allow 30 minutes for writing responses
		ReadHeaderTimeout: 1 * time.Minute,  // Header read timeout
		IdleTimeout:       2 * time.Minute,  // Idle connection timeout
		MaxHeaderBytes:    1 << 20,          // 1 MB max header size
	}

	logger.Info("Server starting", "port", port)
	logger.Info("Upload timeout set to 30 minutes for large backup files")

	e.Server = server
	// Start server
	if err := e.Start(":" + port); err != nil && err != http.ErrServerClosed {
		logger.Error("Server failed to start", "error", err)
		os.Exit(1)
	}
}
