package app

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"git.linuxforward.com/byop/byop-engine/auth"
	"git.linuxforward.com/byop/byop-engine/cloud"
	"git.linuxforward.com/byop/byop-engine/dbstore"
	"git.linuxforward.com/byop/byop-engine/handlers"
	mw "git.linuxforward.com/byop/byop-engine/middleware"
	"git.linuxforward.com/byop/byop-engine/services"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/gin-gonic/gin"
)

func (a *App) initCommonServices() error {
	// Initialize database
	db, err := dbstore.NewSQLiteStore(a.cnf.Database.DSN)
	if err != nil {
		return errors.Wrap(err, "initialize database")
	}
	a.database = db

	// Initialize token store
	a.tokenStore = auth.NewMemoryTokenStore(time.Duration(a.cnf.Auth.CleanupInterval))

	// Initialize authentication service
	a.authService = auth.NewJWTService(
		[]byte(a.cnf.Auth.PrivateKey),
		time.Duration(a.cnf.Auth.TokenDuration),
		a.tokenStore,
		a.database, // Added database argument
	)

	// Initialize providers
	if err := a.loadProviders(); err != nil {
		return errors.Wrap(err, "load providers")
	}

	// If debug mode, create default admin user
	if a.cnf.Debug {
		db.CreateDefaultAdmin(context.Background()) // Added context argument
		a.entry.Info("Debug mode enabled, default admin user created")
		// Output the admin credentials
		a.entry.WithFields(logrus.Fields{
			"email":    "admin@byop.local",
			"password": "admin123",
		}).Info("Default admin credentials")
	}

	// Get Ovh provider
	ovhProvider, _ := cloud.GetProvider("ovh")
	a.previewService = services.NewPreviewService(a.database, ovhProvider, a.cnf, a.registryClient, a.cnf.ReistryUrl, "", "")
	a.builderService = services.NewBuilderService(a.database, a.buildkitClient, a.registryClient, 5)
	a.appImporter = services.NewAppImporter(a.database, a.builderService, a.cnf.ReistryUrl)

	a.entry.Info("Services initialized successfully, including authentication and database manager")
	return nil
}

func (a *App) initHandlers() error {

	// Initialize UserModule
	a.userHandler = handlers.NewUserHandler(a.database)
	// Initialize ClientModule
	a.clientHandler = handlers.NewClientHandler(a.database)

	// Initialize ComponentModule
	a.componentHandler = handlers.NewComponentHandler(a.database, a.builderService, a.cnf.ReistryUrl)

	// Initialize AppModule
	a.appHandler = handlers.NewAppsHandler(a.database, a.previewService, a.appImporter)

	// Initialize DeploymentModule
	a.deploymentHandler = handlers.NewDeploymentHandler(a.database)

	// Initialize authentication handler
	a.authHandler = handlers.NewAuthHandler(a.authService, a.database)

	// Initialize resource handlers
	a.providerHandler = handlers.NewProviderHandler()

	// Initialize PreviewHandler
	a.previewHandler = handlers.NewPreviewHandler(a.previewService, a.database)

	a.entry.Info("Handlers initialized successfully")
	return nil
}

// Updated loadProviders method
func (a *App) loadProviders() error {
	for name, cnf := range a.cnf.Providers {
		// Use the new InitializeProvider function instead of GetProvider + Initialize
		err := cloud.InitializeProvider(name, cnf)
		if err != nil {
			return fmt.Errorf("initialize provider %s: %w", name, err)
		}
		a.entry.WithField("provider", name).Info("Provider initialized")
	}
	a.entry.Info("All providers loaded successfully")
	return nil
}

func (a *App) setupRoutes() {
	// Add CORS middleware to handle all cross-origin requests
	a.rtr.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")

		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		// Allow redirects
		c.Writer.Header().Set("Access-Control-Expose-Headers", "Location")
		c.Writer.Header().Set("Access-Control-Max-Age", "86400") // Cache preflight response for 24 hours
		c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")

		// Handle preflight OPTIONS requests
		if c.Request.Method == http.MethodOptions {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

		c.Next()
	})

	// API version group
	v1 := a.rtr.Group("/api/v1")

	// Auth routes - no middleware required

	// Public routes (no authentication required)
	public := v1.Group("/")
	public.POST("/users", a.userHandler.CreateUser) // Allow user registration without authentication

	// Auth routes - no middleware required
	public.POST("/login", a.authHandler.Login)                // Allow login without authentication
	public.POST("/refresh-token", a.authHandler.RefreshToken) // Allow token refresh without authentication
	public.POST("/logout", a.authHandler.Logout)              // Allow logout without authentication
	public.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok"})
	})

	// Protected routes - require authentication
	protected := v1.Group("/")
	protected.Use(mw.Auth(a.authService)) // Auth middleware with service dependency

	// Register resource routes
	providers := protected.Group("/providers")
	a.providerHandler.RegisterRoutes(providers)

	// Client routes - registering both with and without trailing slash
	clients := protected.Group("/clients")
	clients.GET("", a.clientHandler.ListClients)
	clients.POST("", a.clientHandler.CreateClient)
	clients.GET("/:id", a.clientHandler.GetClient)
	clients.PUT("/:id", a.clientHandler.UpdateClient)
	clients.DELETE("/:id", a.clientHandler.DeleteClient)
	clients.GET("/:id/deployments", a.clientHandler.GetClientDeployments)

	// User routes - registering both with and without trailing slash
	users := protected.Group("/users")
	users.GET("", a.userHandler.ListUsers)
	users.GET("/:id", a.userHandler.GetUser)
	users.PUT("/:id", a.userHandler.UpdateUser)
	users.DELETE("/:id", a.userHandler.DeleteUser)
	users.GET("/:id/deployments", a.userHandler.GetUserDeployments)

	// Component routes (formerly Apps)
	components := protected.Group("/components")
	components.GET("", a.componentHandler.ListComponents)
	components.POST("", a.componentHandler.CreateComponent)
	components.GET("/:id", a.componentHandler.GetComponent)
	components.PUT("/:id", a.componentHandler.UpdateComponent)
	components.DELETE("/:id", a.componentHandler.DeleteComponent)
	components.GET("/:id/deployments", a.componentHandler.GetComponentDeployments)

	// App routes (formerly Templates)
	apps := protected.Group("/apps")
	apps.GET("", a.appHandler.ListApps)
	apps.POST("", a.appHandler.CreateApp)
	apps.GET("/:id", a.appHandler.GetApp)
	apps.PUT("/:id", a.appHandler.UpdateApp)
	apps.DELETE("/:id", a.appHandler.DeleteApp)
	apps.GET("/:id/deployments", a.appHandler.GetAppDeployments)
	// App preview route
	apps.POST("/:id/preview", a.appHandler.CreateAppPreview)
	apps.GET("/:id/preview", a.appHandler.GetAppPreview)
	apps.DELETE("/:id/preview", a.appHandler.DeleteAppPreview)
	// App import routes
	apps.POST("/import/review", a.appHandler.ImportReview)
	apps.POST("/import/create", a.appHandler.ImportCreate)

	// Deployment routes - need to handle both versions
	deployments := protected.Group("/deployments")
	deployments.GET("", a.deploymentHandler.ListDeployments)
	deployments.POST("", a.deploymentHandler.CreateDeployment)
	deployments.GET("/:id", a.deploymentHandler.GetDeployment)
	deployments.PUT("/:id", a.deploymentHandler.UpdateDeployment)
	deployments.DELETE("/:id", a.deploymentHandler.DeleteDeployment)
	deployments.PUT("/:id/status", a.deploymentHandler.UpdateDeploymentStatus)
	// deployments.GET("/by-client/:clientId", a.deploymentHandler.GetDeploymentsByClient)
	// deployments.GET("/by-app/:appId", a.deploymentHandler.GetDeploymentsByTemplate) // Was by-template
	// deployments.GET("/by-user/:userId", a.deploymentHandler.GetDeploymentsByUser)
	// // Add other resource routes as needed

	a.entry.Info("Routes configured successfully")
}
