package main

import (
	"log"

	"github.com/breakpilot/billing-service/internal/config"
	"github.com/breakpilot/billing-service/internal/database"
	"github.com/breakpilot/billing-service/internal/handlers"
	"github.com/breakpilot/billing-service/internal/middleware"
	"github.com/breakpilot/billing-service/internal/services"
	"github.com/gin-gonic/gin"
)

func main() {
	// Load configuration
	cfg, err := config.Load()
	if err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}

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

	// Run migrations
	if err := database.Migrate(db); err != nil {
		log.Fatalf("Failed to run migrations: %v", err)
	}

	// Setup Gin router
	if cfg.Environment == "production" {
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.Default()

	// Global middleware
	router.Use(middleware.CORS())
	router.Use(middleware.RequestLogger())
	router.Use(middleware.RateLimiter())

	// Health check (no auth required)
	router.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"status":  "healthy",
			"service": "billing-service",
			"version": "1.0.0",
		})
	})

	// Initialize services
	subscriptionService := services.NewSubscriptionService(db)

	// Create Stripe service (mock or real depending on config)
	var stripeService *services.StripeService
	if cfg.IsMockMode() {
		log.Println("Starting in MOCK MODE - Stripe API calls will be simulated")
		stripeService = services.NewMockStripeService(
			cfg.BillingSuccessURL,
			cfg.BillingCancelURL,
			cfg.TrialPeriodDays,
			subscriptionService,
		)
	} else {
		stripeService = services.NewStripeService(
			cfg.StripeSecretKey,
			cfg.StripeWebhookSecret,
			cfg.BillingSuccessURL,
			cfg.BillingCancelURL,
			cfg.TrialPeriodDays,
			subscriptionService,
		)
	}

	entitlementService := services.NewEntitlementService(db, subscriptionService)
	usageService := services.NewUsageService(db, entitlementService)

	// Initialize handlers
	billingHandler := handlers.NewBillingHandler(
		db,
		subscriptionService,
		stripeService,
		entitlementService,
		usageService,
	)
	webhookHandler := handlers.NewWebhookHandler(
		db,
		cfg.StripeWebhookSecret,
		subscriptionService,
		entitlementService,
	)

	// API v1 routes
	v1 := router.Group("/api/v1/billing")
	{
		// Stripe webhook (no auth - uses Stripe signature)
		v1.POST("/webhook", webhookHandler.HandleStripeWebhook)

		// =============================================
		// User Endpoints (require JWT auth)
		// =============================================
		user := v1.Group("")
		user.Use(middleware.AuthMiddleware(cfg.JWTSecret))
		{
			// Subscription status and management
			user.GET("/status", billingHandler.GetBillingStatus)
			user.GET("/plans", billingHandler.GetPlans)
			user.POST("/trial/start", billingHandler.StartTrial)
			user.POST("/change-plan", billingHandler.ChangePlan)
			user.POST("/cancel", billingHandler.CancelSubscription)
			user.GET("/portal", billingHandler.GetCustomerPortal)
		}

		// =============================================
		// Internal Endpoints (service-to-service)
		// =============================================
		internal := v1.Group("")
		internal.Use(middleware.InternalAPIKeyMiddleware(cfg.InternalAPIKey))
		{
			// Entitlements
			internal.GET("/entitlements/:userId", billingHandler.GetEntitlements)
			internal.GET("/entitlements/check/:userId/:feature", billingHandler.CheckEntitlement)

			// Usage tracking
			internal.POST("/usage/track", billingHandler.TrackUsage)
			internal.GET("/usage/check/:userId/:type", billingHandler.CheckUsage)
		}
	}

	// Start server
	port := cfg.Port
	if port == "" {
		port = "8083"
	}

	log.Printf("Starting Billing Service on port %s", port)
	if err := router.Run(":" + port); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
