package app

import (
	"context"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/scheduler"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/leaderelection"
)

// Application represents the main application
type Application struct {
	cfg                *config.Config
	logger             *zap.Logger
	server             *http.Server
	leaderElection     leaderelection.LeaderElection
	quotaScheduler     *scheduler.QuotaResetScheduler
	ipCleanupScheduler *scheduler.IPCleanupScheduler
}

// ProvideApplication creates a new Application
func ProvideApplication(
	cfg *config.Config,
	logger *zap.Logger,
	server *http.Server,
	leaderElection leaderelection.LeaderElection,
	quotaScheduler *scheduler.QuotaResetScheduler,
	ipCleanupScheduler *scheduler.IPCleanupScheduler,
) *Application {
	return &Application{
		cfg:                cfg,
		logger:             logger,
		server:             server,
		leaderElection:     leaderElection,
		quotaScheduler:     quotaScheduler,
		ipCleanupScheduler: ipCleanupScheduler,
	}
}

// Run starts the application
func (a *Application) Run(ctx context.Context) error {
	a.logger.Info("")
	a.logger.Info("╔═══════════════════════════════════════════════╗")
	a.logger.Info("║        MaplePress Backend Starting...        ║")
	a.logger.Info("╚═══════════════════════════════════════════════╝")
	a.logger.Info("",
		zap.String("environment", a.cfg.App.Environment),
		zap.String("version", a.cfg.App.Version))
	a.logger.Info("")

	// Start leader election in background if enabled
	if a.cfg.LeaderElection.Enabled {
		go func() {
			a.logger.Info("starting leader election")
			if err := a.leaderElection.Start(ctx); err != nil {
				a.logger.Error("leader election stopped", zap.Error(err))
			}
		}()
	} else {
		a.logger.Warn("leader election is DISABLED - all schedulers will run on every instance")
	}

	// Start quota reset scheduler
	if err := a.quotaScheduler.Start(); err != nil {
		a.logger.Error("failed to start quota scheduler", zap.Error(err))
		return err
	}

	// Start IP cleanup scheduler for GDPR compliance
	if err := a.ipCleanupScheduler.Start(); err != nil {
		a.logger.Error("failed to start IP cleanup scheduler", zap.Error(err))
		return err
	}

	return a.server.Start()
}

// Shutdown gracefully shuts down the application
func (a *Application) Shutdown(ctx context.Context) error {
	a.logger.Info("shutting down MaplePress Backend")

	// Stop leader election first if enabled
	if a.cfg.LeaderElection.Enabled {
		a.logger.Info("stopping leader election")
		if err := a.leaderElection.Stop(); err != nil {
			a.logger.Error("failed to stop leader election", zap.Error(err))
		}
	}

	// Stop quota scheduler
	a.quotaScheduler.Stop()

	// Stop IP cleanup scheduler
	a.ipCleanupScheduler.Stop()

	if err := a.server.Shutdown(ctx); err != nil {
		a.logger.Error("failed to shutdown server", zap.Error(err))
		return err
	}

	// Sync logger before exit
	a.logger.Sync()

	return nil
}
