package mysql

import (
	"context"
	"database/sql"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/wallet-service/internal/domain/ledger"
	resourcedomain "hyapp/services/wallet-service/internal/domain/resource"
	"strings"
	"time"
)

// UpdateAdminVipLevels 保存完整 10 级 VIP 配置。
func (r *Repository) UpdateAdminVipLevels(ctx context.Context, levels []ledger.AdminVipLevelCommand, operatorUserID int64) ([]ledger.VipLevel, error) {
	if r == nil || r.db == nil {
		return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	if operatorUserID <= 0 {
		return nil, xerr.New(xerr.InvalidArgument, "operator_user_id is required")
	}
	normalized, err := normalizeAdminVipLevelCommands(levels)
	if err != nil {
		return nil, err
	}

	tx, err := r.db.BeginTx(ctx, nil)
	if err != nil {
		return nil, err
	}
	defer func() { _ = tx.Rollback() }()

	nowMs := time.Now().UnixMilli()
	for _, level := range normalized {
		if level.Status == ledger.VipStatusActive {
			if err := r.requireActiveResourceGroup(ctx, tx, level.RewardResourceGroupID); err != nil {
				return nil, err
			}
		}
		if _, err := tx.ExecContext(ctx, `
			INSERT INTO vip_levels (
			   app_code, level, name, status, price_coin, duration_ms, reward_resource_group_id,
			   required_recharge_coin_amount, sort_order, created_at_ms, updated_at_ms
			 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
			 ON DUPLICATE KEY UPDATE
			   name = VALUES(name),
			   status = VALUES(status),
			   price_coin = VALUES(price_coin),
			   duration_ms = VALUES(duration_ms),
			   reward_resource_group_id = VALUES(reward_resource_group_id),
			   required_recharge_coin_amount = VALUES(required_recharge_coin_amount),
			   sort_order = VALUES(sort_order),
			   updated_at_ms = VALUES(updated_at_ms)`,
			appcode.FromContext(ctx),
			level.Level,
			level.Name,
			level.Status,
			level.PriceCoin,
			level.DurationMS,
			level.RewardResourceGroupID,
			level.RequiredRechargeCoinAmount,
			level.SortOrder,
			nowMs,
			nowMs,
		); err != nil {
			return nil, err
		}
	}
	if err := tx.Commit(); err != nil {
		return nil, err
	}
	return r.ListAdminVipLevels(ctx)
}

func normalizeAdminVipLevelCommands(levels []ledger.AdminVipLevelCommand) ([]ledger.AdminVipLevelCommand, error) {
	if len(levels) != 10 {
		return nil, xerr.New(xerr.InvalidArgument, "vip config requires exactly 10 levels")
	}
	byLevel := make(map[int32]ledger.AdminVipLevelCommand, 10)
	for _, level := range levels {
		level.Name = strings.TrimSpace(level.Name)
		level.Status = strings.ToLower(strings.TrimSpace(level.Status))
		if level.Status == "" {
			level.Status = ledger.VipStatusDisabled
		}
		if level.Level < 1 || level.Level > 10 {
			return nil, xerr.New(xerr.InvalidArgument, "vip level must be between 1 and 10")
		}
		if _, exists := byLevel[level.Level]; exists {
			return nil, xerr.New(xerr.InvalidArgument, "vip level is duplicated")
		}
		if level.Level <= 5 {
			level.RequiredRechargeCoinAmount = 0
		}
		if err := validateAdminVipLevelCommand(level); err != nil {
			return nil, err
		}
		byLevel[level.Level] = level
	}
	normalized := make([]ledger.AdminVipLevelCommand, 0, 10)
	for level := int32(1); level <= 10; level++ {
		item, ok := byLevel[level]
		if !ok {
			return nil, xerr.New(xerr.InvalidArgument, "vip config requires levels 1 to 10")
		}
		normalized = append(normalized, item)
	}
	return normalized, nil
}

func validateAdminVipLevelCommand(level ledger.AdminVipLevelCommand) error {
	if level.Name == "" {
		return xerr.New(xerr.InvalidArgument, "vip level name is required")
	}
	switch level.Status {
	case ledger.VipStatusActive, ledger.VipStatusDisabled:
	default:
		return xerr.New(xerr.InvalidArgument, "vip level status is invalid")
	}
	if level.PriceCoin < 0 || level.DurationMS <= 0 || level.RewardResourceGroupID < 0 || level.RequiredRechargeCoinAmount < 0 {
		return xerr.New(xerr.InvalidArgument, "vip level config is invalid")
	}
	if level.Status != ledger.VipStatusActive {
		return nil
	}
	if level.PriceCoin <= 0 {
		return xerr.New(xerr.InvalidArgument, "active vip level price_coin must be greater than zero")
	}
	if level.RewardResourceGroupID <= 0 {
		return xerr.New(xerr.InvalidArgument, "active vip level reward_resource_group_id is required")
	}
	if level.Level >= 6 && level.RequiredRechargeCoinAmount <= 0 {
		return xerr.New(xerr.InvalidArgument, "vip level 6-10 requires recharge threshold")
	}
	return nil
}

func (r *Repository) requireActiveResourceGroup(ctx context.Context, tx *sql.Tx, groupID int64) error {
	group, err := r.getResourceGroup(ctx, tx, groupID, true)
	if err != nil {
		return err
	}
	if group.Status != resourcedomain.StatusActive {
		return xerr.New(xerr.Conflict, "vip reward group is disabled")
	}
	return nil
}
