package site

import (
	"context"
	"fmt"
	"time"

	"go.uber.org/zap"

	domainsite "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/site"
)

// ResetMonthlyUsageUseCase handles resetting monthly usage counters for all sites (for billing cycles)
type ResetMonthlyUsageUseCase struct {
	siteRepo domainsite.Repository
	logger   *zap.Logger
}

// ProvideResetMonthlyUsageUseCase creates a new ResetMonthlyUsageUseCase
func ProvideResetMonthlyUsageUseCase(
	siteRepo domainsite.Repository,
	logger *zap.Logger,
) *ResetMonthlyUsageUseCase {
	return &ResetMonthlyUsageUseCase{
		siteRepo: siteRepo,
		logger:   logger.Named("reset-monthly-usage-usecase"),
	}
}

// ResetUsageOutput is the output after resetting usage counters
type ResetUsageOutput struct {
	ProcessedSites int       `json:"processed_sites"`
	ResetCount     int       `json:"reset_count"`
	FailedCount    int       `json:"failed_count"`
	ProcessedAt    time.Time `json:"processed_at"`
}

// Execute resets monthly usage counters for all sites (for billing cycles)
func (uc *ResetMonthlyUsageUseCase) Execute(ctx context.Context) (*ResetUsageOutput, error) {
	uc.logger.Info("starting monthly usage counter reset for all sites")

	startTime := time.Now()
	processedSites := 0
	resetCount := 0
	failedCount := 0

	// Pagination settings
	const pageSize = 100
	var pageState []byte

	// Iterate through all sites using pagination
	for {
		// Get a batch of sites
		sites, nextPageState, err := uc.siteRepo.GetAllSitesForUsageReset(ctx, pageSize, pageState)
		if err != nil {
			uc.logger.Error("failed to get sites for usage reset", zap.Error(err))
			return nil, fmt.Errorf("failed to get sites: %w", err)
		}

		// Process each site in the batch
		for _, site := range sites {
			processedSites++

			// Check if usage needs to be reset (monthly billing cycle)
			now := time.Now()
			needsReset := false

			// Check if it's been a month since last reset
			if site.LastResetAt.AddDate(0, 1, 0).Before(now) {
				needsReset = true
			}

			if !needsReset {
				uc.logger.Debug("site usage not due for reset",
					zap.String("site_id", site.ID.String()),
					zap.String("domain", site.Domain),
					zap.Time("last_reset_at", site.LastResetAt))
				continue
			}

			// Reset the usage counters
			site.ResetMonthlyUsage()

			// Update the site in database
			if err := uc.siteRepo.UpdateUsage(ctx, site); err != nil {
				uc.logger.Error("failed to reset usage for site",
					zap.String("site_id", site.ID.String()),
					zap.String("domain", site.Domain),
					zap.Error(err))
				failedCount++
				continue
			}

			resetCount++
			uc.logger.Debug("reset usage for site",
				zap.String("site_id", site.ID.String()),
				zap.String("domain", site.Domain),
				zap.Time("last_reset_at", site.LastResetAt))
		}

		// Check if there are more pages
		if len(nextPageState) == 0 {
			break
		}

		pageState = nextPageState

		uc.logger.Info("processed batch of sites",
			zap.Int("batch_size", len(sites)),
			zap.Int("total_processed", processedSites),
			zap.Int("reset_count", resetCount),
			zap.Int("failed_count", failedCount))
	}

	uc.logger.Info("monthly usage counter reset completed",
		zap.Int("processed_sites", processedSites),
		zap.Int("reset_count", resetCount),
		zap.Int("failed_count", failedCount),
		zap.Duration("duration", time.Since(startTime)))

	return &ResetUsageOutput{
		ProcessedSites: processedSites,
		ResetCount:     resetCount,
		FailedCount:    failedCount,
		ProcessedAt:    time.Now(),
	}, nil
}
