package packagepkg

import (
	"context"
	"sync/atomic"

	packagedomain "github.com/break/junhong_cmp_fiber/internal/domain/package"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

var historicalTermsFallbackCount atomic.Uint64

// ResolveUsageTerms 优先读取使用记录快照，仅对完整空快照的历史记录显式回退。
func ResolveUsageTerms(usage *model.PackageUsage, pkg *model.Package, logger *zap.Logger) (packagedomain.TermsSnapshot, error) {
	terms := packagedomain.TermsSnapshotFromUsage(usage)
	if terms.IsValid() {
		return terms, nil
	}
	if !isEmptyHistoricalTerms(usage) {
		if logger != nil {
			logger.Error("套餐使用记录计时快照异常", zap.Uint("package_usage_id", usage.ID), zap.Uint("package_id", usage.PackageID))
		}
		return packagedomain.TermsSnapshot{}, errors.New(errors.CodeInternalError, "套餐使用记录计时快照异常")
	}
	fallback, err := packagedomain.ResolveTermsSnapshot(pkg, nil)
	if err != nil {
		return packagedomain.TermsSnapshot{}, err
	}
	historicalTermsFallbackCount.Add(1)
	if logger != nil {
		logger.Warn("历史套餐使用记录缺少计时快照，回退套餐当前配置",
			zap.Uint("package_usage_id", usage.ID), zap.Uint("package_id", usage.PackageID),
			zap.Uint64("historical_terms_fallback_count", historicalTermsFallbackCount.Load()))
	}
	return fallback, nil
}

// HistoricalTermsFallbackCount 返回历史计时条款回退累计次数。
func HistoricalTermsFallbackCount() uint64 {
	return historicalTermsFallbackCount.Load()
}

// ResolveTermsFromTx 在给定事务内查询分配覆盖并解析计时条款快照。
// 必须在事务内调用，确保分配读取与 PackageUsage 写入在同一连接，避免快照与提交值不一致。
func ResolveTermsFromTx(ctx context.Context, tx *gorm.DB, pkg *model.Package, sellerShopID *uint) (packagedomain.TermsSnapshot, error) {
	var allocation *model.ShopPackageAllocation
	if sellerShopID != nil && *sellerShopID > 0 {
		store := postgres.NewShopPackageAllocationStore(tx)
		found, err := store.GetByShopAndPackageForSystem(ctx, *sellerShopID, pkg.ID)
		if err != nil && err != gorm.ErrRecordNotFound {
			return packagedomain.TermsSnapshot{}, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐分配失败")
		}
		if err == nil {
			allocation = found
		}
	}
	return packagedomain.ResolveTermsSnapshot(pkg, allocation)
}

func isEmptyHistoricalTerms(usage *model.PackageUsage) bool {
	return usage.ExpiryBaseSnapshot == "" && usage.CalendarTypeSnapshot == "" &&
		usage.DurationMonthsSnapshot == 0 && usage.DurationDaysSnapshot == 0
}
