package postgres

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

type PackageUsageStore struct {
	db    *gorm.DB
	redis *redis.Client
}

func NewPackageUsageStore(db *gorm.DB, redis *redis.Client) *PackageUsageStore {
	return &PackageUsageStore{
		db:    db,
		redis: redis,
	}
}

// Create 创建套餐使用记录（支持新字段：priority, master_usage_id, has_independent_expiry, pending_realname_activation, data_reset_cycle）
// 注意：Status=0 是合法值（待生效），需要明确指定 status 字段以覆盖数据库默认值 1
func (s *PackageUsageStore) Create(ctx context.Context, usage *model.PackageUsage) error {
	// GORM 对零值字段有特殊处理，先创建然后立即更新 status 字段确保正确设置
	if err := s.db.WithContext(ctx).Omit("status").Create(usage).Error; err != nil {
		return err
	}
	// 明确更新 status 字段（包括零值）
	return s.db.WithContext(ctx).Model(usage).Update("status", usage.Status).Error
}

// GetByID 根据ID查询套餐使用记录
func (s *PackageUsageStore) GetByID(ctx context.Context, id uint) (*model.PackageUsage, error) {
	var usage model.PackageUsage
	if err := s.db.WithContext(ctx).First(&usage, id).Error; err != nil {
		return nil, err
	}
	return &usage, nil
}

// GetByIDForCarrier 根据载体查询套餐使用记录。
func (s *PackageUsageStore) GetByIDForCarrier(ctx context.Context, id uint, carrierType string, carrierID uint) (*model.PackageUsage, error) {
	var usage model.PackageUsage
	query := s.db.WithContext(ctx).Where("id = ?", id)
	query = applyPackageUsageCarrierFilter(query, carrierType, carrierID)
	if err := query.First(&usage).Error; err != nil {
		return nil, err
	}
	return &usage, nil
}

// Update 更新套餐使用记录
func (s *PackageUsageStore) Update(ctx context.Context, usage *model.PackageUsage) error {
	return s.db.WithContext(ctx).Save(usage).Error
}

// GetActiveMainPackage 查询载体的生效中主套餐
// carrierType: "iot_card" 或 "device"
// carrierID: iot_card_id 或 device_id
func (s *PackageUsageStore) GetActiveMainPackage(ctx context.Context, carrierType string, carrierID uint) (*model.PackageUsage, error) {
	var usage model.PackageUsage
	query := s.db.WithContext(ctx).
		Where("status = ?", constants.PackageUsageStatusActive).
		Where("master_usage_id IS NULL"). // 主套餐的 master_usage_id 为 NULL
		Order("priority ASC, activated_at ASC")

	if carrierType == "iot_card" {
		query = query.Where("iot_card_id = ?", carrierID)
	} else if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	}

	if err := query.First(&usage).Error; err != nil {
		return nil, err
	}
	return &usage, nil
}

// GetNextPendingMainPackage 查询下一个待生效主套餐（按 priority ASC 排序）
func (s *PackageUsageStore) GetNextPendingMainPackage(ctx context.Context, carrierType string, carrierID uint) (*model.PackageUsage, error) {
	var usage model.PackageUsage
	query := s.db.WithContext(ctx).
		Where("status = ?", constants.PackageUsageStatusPending).
		Where("master_usage_id IS NULL"). // 主套餐
		Order("priority ASC, created_at ASC")

	if carrierType == "iot_card" {
		query = query.Where("iot_card_id = ?", carrierID)
	} else if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	}

	if err := query.First(&usage).Error; err != nil {
		return nil, err
	}
	return &usage, nil
}

// GetActivePackages 查询生效中的主套餐和加油包（按优先级排序：priority ASC, expires_at ASC, activated_at ASC）
func (s *PackageUsageStore) GetActivePackages(ctx context.Context, carrierType string, carrierID uint) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage
	query := s.db.WithContext(ctx).
		Where("status = ?", constants.PackageUsageStatusActive).
		Order("priority ASC, expires_at ASC, activated_at ASC")

	if carrierType == "iot_card" {
		query = query.Where("iot_card_id = ?", carrierID)
	} else if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	}

	if err := query.Find(&usages).Error; err != nil {
		return nil, err
	}
	return usages, nil
}

// GetAddonsByMasterID 查询主套餐下的所有加油包
func (s *PackageUsageStore) GetAddonsByMasterID(ctx context.Context, masterUsageID uint) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage
	if err := s.db.WithContext(ctx).
		Where("master_usage_id = ?", masterUsageID).
		Order("priority ASC").
		Find(&usages).Error; err != nil {
		return nil, err
	}
	return usages, nil
}

// ListActiveByOrderID 查询订单下所有非终态套餐记录（status NOT IN 已过期=3, 已失效=4）
func (s *PackageUsageStore) ListActiveByOrderID(ctx context.Context, orderID uint) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage
	err := s.db.WithContext(ctx).
		Where("order_id = ? AND status NOT IN ?", orderID, []int{3, 4}).
		Find(&usages).Error
	return usages, err
}

// BatchUpdateStatus 批量更新加油包状态
func (s *PackageUsageStore) BatchUpdateStatus(ctx context.Context, ids []uint, status int) error {
	if len(ids) == 0 {
		return nil
	}
	return s.db.WithContext(ctx).
		Model(&model.PackageUsage{}).
		Where("id IN ?", ids).
		Update("status", status).Error
}

// UpdateDataUsage 更新套餐流量使用（支持事务）
// incrementMB: 增量流量（MB）
func (s *PackageUsageStore) UpdateDataUsage(ctx context.Context, id uint, incrementMB int64) error {
	return s.db.WithContext(ctx).
		Model(&model.PackageUsage{}).
		Where("id = ?", id).
		Update("data_usage_mb", gorm.Expr("data_usage_mb + ?", incrementMB)).Error
}

// UpdateExpiresAtForCarrier 按载体条件更新套餐过期时间。
func (s *PackageUsageStore) UpdateExpiresAtForCarrier(ctx context.Context, id uint, carrierType string, carrierID uint, expiresAt time.Time) (int64, error) {
	query := s.db.WithContext(ctx).
		Model(&model.PackageUsage{}).
		Where("id = ?", id)
	query = applyPackageUsageCarrierFilter(query, carrierType, carrierID)

	result := query.Updates(map[string]any{
		"expires_at": expiresAt,
	})
	return result.RowsAffected, result.Error
}

// UpdateDataUsageForCarrier 按载体条件更新套餐已用量。
func (s *PackageUsageStore) UpdateDataUsageForCarrier(ctx context.Context, id uint, carrierType string, carrierID uint, dataUsageMB int64, status *int) (int64, error) {
	query := s.db.WithContext(ctx).
		Model(&model.PackageUsage{}).
		Where("id = ?", id)
	query = applyPackageUsageCarrierFilter(query, carrierType, carrierID)

	updates := map[string]any{
		"data_usage_mb": dataUsageMB,
	}
	if status != nil {
		updates["status"] = *status
	}

	result := query.Updates(updates)
	return result.RowsAffected, result.Error
}

// GetPackagesForReset 查询需要重置的套餐（WHERE next_reset_at <= NOW）
func (s *PackageUsageStore) GetPackagesForReset(ctx context.Context, limit int) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage
	now := time.Now()
	query := s.db.WithContext(ctx).
		Where("next_reset_at IS NOT NULL").
		Where("next_reset_at <= ?", now).
		Where("status = ?", constants.PackageUsageStatusActive).
		Order("next_reset_at ASC")

	if limit > 0 {
		query = query.Limit(limit)
	}

	if err := query.Find(&usages).Error; err != nil {
		return nil, err
	}
	return usages, nil
}

// ResetDataUsage 重置流量（更新 last_reset_at 和 next_reset_at）
func (s *PackageUsageStore) ResetDataUsage(ctx context.Context, id uint, lastResetAt, nextResetAt time.Time) error {
	return s.db.WithContext(ctx).
		Model(&model.PackageUsage{}).
		Where("id = ?", id).
		Updates(map[string]any{
			"data_usage_mb": 0,
			"last_reset_at": lastResetAt,
			"next_reset_at": nextResetAt,
		}).Error
}

// HasValidByCarrier 检查载体是否有有效套餐（仅 status = 生效中）
// carrierType: "iot_card" 或 "device"
func (s *PackageUsageStore) HasValidByCarrier(ctx context.Context, carrierType string, carrierID uint) (bool, error) {
	var count int64
	query := s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Where("status = ?", constants.PackageUsageStatusActive)
	if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	} else {
		query = query.Where("iot_card_id = ?", carrierID)
	}
	if err := query.Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

// GetActiveOrDepletedByCarrier 查询载体的活跃或耗尽套餐（用于流量耗尽检测）
// ORDER BY status ASC 优先返回活跃套餐（status=1），有活跃套餐时先评估活跃套餐的流量上限
// 返回 gorm.ErrRecordNotFound 表示无活跃或耗尽套餐（不判定为流量耗尽）
func (s *PackageUsageStore) GetActiveOrDepletedByCarrier(ctx context.Context, carrierType string, carrierID uint) (*model.PackageUsage, error) {
	var pkg model.PackageUsage
	query := s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Where("status IN ?", []int{
			constants.PackageUsageStatusActive,   // 生效中
			constants.PackageUsageStatusDepleted, // 已用完
		}).
		Order("status ASC").
		Limit(1)
	if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	} else {
		query = query.Where("iot_card_id = ?", carrierID)
	}
	if err := query.First(&pkg).Error; err != nil {
		return nil, err
	}
	return &pkg, nil
}

// ListActiveOrDepletedByCarrier 查询载体下所有生效中或已用完套餐。
func (s *PackageUsageStore) ListActiveOrDepletedByCarrier(ctx context.Context, carrierType string, carrierID uint) ([]*model.PackageUsage, error) {
	var packages []*model.PackageUsage
	query := s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Where("status IN ?", []int{
			constants.PackageUsageStatusActive,
			constants.PackageUsageStatusDepleted,
		}).
		Order("CASE WHEN master_usage_id IS NOT NULL THEN 0 ELSE 1 END, priority ASC, activated_at ASC")

	if carrierType == "device" {
		query = query.Where("device_id = ?", carrierID)
	} else {
		query = query.Where("iot_card_id = ?", carrierID)
	}

	if err := query.Find(&packages).Error; err != nil {
		return nil, err
	}
	return packages, nil
}

// ListByCarrier 查询载体的套餐使用记录（可按状态筛选）
func (s *PackageUsageStore) ListByCarrier(ctx context.Context, carrierType string, carrierID uint, status *int) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage
	query := s.db.WithContext(ctx).Order("priority ASC, created_at DESC")

	query = applyPackageUsageCarrierFilter(query, carrierType, carrierID)
	if status != nil {
		query = query.Where("status = ?", *status)
	}

	if err := query.Find(&usages).Error; err != nil {
		return nil, err
	}
	return usages, nil
}

// GetCurrentGenerationUsagesForSummary 查询当前世代内所有已激活过的套餐记录（含加油包），用于流量汇总。
// 当前世代定义：status∈{1,2,3,4} 中 generation 最大值所在的那一批记录。
// 返回计算所需字段：DataUsageMB、DataLimitMB、VirtualTotalMBSnapshot、DisplayGainRatioSnapshot、EnableVirtualDataSnapshot。
func (s *PackageUsageStore) GetCurrentGenerationUsagesForSummary(ctx context.Context, carrierType string, carrierID uint) ([]*model.PackageUsage, error) {
	var usages []*model.PackageUsage

	// 子查询取当前世代编号
	subQuery := s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Select("MAX(generation)").
		Where("status IN ?", []int{
			constants.PackageUsageStatusActive,
			constants.PackageUsageStatusDepleted,
			constants.PackageUsageStatusExpired,
			constants.PackageUsageStatusInvalidated,
		})
	subQuery = applyPackageUsageCarrierFilter(subQuery, carrierType, carrierID)

	query := s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Select("data_usage_mb, data_limit_mb, virtual_total_mb_snapshot, display_gain_ratio_snapshot, enable_virtual_data_snapshot").
		Where("status IN ?", []int{
			constants.PackageUsageStatusActive,
			constants.PackageUsageStatusDepleted,
			constants.PackageUsageStatusExpired,
			constants.PackageUsageStatusInvalidated,
		}).
		Where("generation = (?)", subQuery)
	query = applyPackageUsageCarrierFilter(query, carrierType, carrierID)

	if err := query.Find(&usages).Error; err != nil {
		return nil, err
	}
	return usages, nil
}

func applyPackageUsageCarrierFilter(query *gorm.DB, carrierType string, carrierID uint) *gorm.DB {
	if carrierType == "iot_card" {
		return query.Where("iot_card_id = ?", carrierID)
	}
	if carrierType == "device" {
		return query.Where("device_id = ?", carrierID)
	}
	return query
}
