package wallet

import (
	"context"
	"strings"
	"time"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/wallet-service/internal/domain/ledger"
)

const vipDailyCoinRebateTaskDayLayout = "2006-01-02"

// ProcessVipDailyCoinRebateBatch 只接受 UTC 日期，不接受时区偏移。空 task_day 使用 wallet owner
// 当前 UTC 日期，使调度方无需也不能自行决定业务切日。
func (s *Service) ProcessVipDailyCoinRebateBatch(ctx context.Context, command ledger.ProcessVipDailyCoinRebateBatchCommand) (ledger.ProcessVipDailyCoinRebateBatchResult, error) {
	if s.repository == nil {
		return ledger.ProcessVipDailyCoinRebateBatchResult{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	now := s.now().UTC()
	command.NowMS = now.UnixMilli()
	command.TaskDay = strings.TrimSpace(command.TaskDay)
	if command.TaskDay == "" {
		command.TaskDay = now.Format(vipDailyCoinRebateTaskDayLayout)
	}
	dayStart, err := time.ParseInLocation(vipDailyCoinRebateTaskDayLayout, command.TaskDay, time.UTC)
	if err != nil || dayStart.Format(vipDailyCoinRebateTaskDayLayout) != command.TaskDay {
		return ledger.ProcessVipDailyCoinRebateBatchResult{}, xerr.New(xerr.InvalidArgument, "task_day must be an UTC date in YYYY-MM-DD")
	}
	if dayStart.After(now) {
		return ledger.ProcessVipDailyCoinRebateBatchResult{}, xerr.New(xerr.InvalidArgument, "future vip rebate task_day is not allowed")
	}
	if command.BatchSize <= 0 {
		command.BatchSize = 100
	}
	if command.BatchSize > 500 {
		command.BatchSize = 500
	}
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.ProcessVipDailyCoinRebateBatch(ctx, command)
}

// GetMyCurrentVipDailyCoinRebate 查询当前 UTC 日返现；没有记录是正常状态，以 found=false 表达。
func (s *Service) GetMyCurrentVipDailyCoinRebate(ctx context.Context, userID int64) (ledger.VipDailyCoinRebate, bool, error) {
	if userID <= 0 {
		return ledger.VipDailyCoinRebate{}, false, xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if s.repository == nil {
		return ledger.VipDailyCoinRebate{}, false, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	nowMS := s.now().UTC().UnixMilli()
	ctx = appcode.WithContext(ctx, appcode.FromContext(ctx))
	return s.repository.GetMyCurrentVipDailyCoinRebate(ctx, userID, nowMS)
}

// ListMyVipDailyCoinRebateStatuses 返回用户历史记录；expired 由 wallet owner 使用当前 UTC 时钟投影。
func (s *Service) ListMyVipDailyCoinRebateStatuses(ctx context.Context, query ledger.ListVipDailyCoinRebateStatusesQuery) ([]ledger.VipDailyCoinRebate, int64, error) {
	if query.UserID <= 0 {
		return nil, 0, xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if s.repository == nil {
		return nil, 0, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	query.AppCode = appcode.Normalize(query.AppCode)
	if query.Page <= 0 {
		query.Page = 1
	}
	if query.PageSize <= 0 {
		query.PageSize = 20
	}
	if query.PageSize > 100 {
		query.PageSize = 100
	}
	if len(query.RebateIDs) > 100 {
		return nil, 0, xerr.New(xerr.InvalidArgument, "rebate_ids cannot contain more than 100 items")
	}
	seenRebateIDs := make(map[string]struct{}, len(query.RebateIDs))
	normalizedRebateIDs := make([]string, 0, len(query.RebateIDs))
	for _, rebateID := range query.RebateIDs {
		rebateID = strings.TrimSpace(rebateID)
		if rebateID == "" || len(rebateID) > 96 {
			return nil, 0, xerr.New(xerr.InvalidArgument, "rebate_ids contains an invalid id")
		}
		if _, exists := seenRebateIDs[rebateID]; exists {
			continue
		}
		seenRebateIDs[rebateID] = struct{}{}
		normalizedRebateIDs = append(normalizedRebateIDs, rebateID)
	}
	query.RebateIDs = normalizedRebateIDs
	query.NowMS = s.now().UTC().UnixMilli()
	ctx = appcode.WithContext(ctx, query.AppCode)
	return s.repository.ListMyVipDailyCoinRebateStatuses(ctx, query)
}

// ClaimVipDailyCoinRebate 只校验命令形状；可领取窗口、金额、付费 VIP 快照和余额变更均在
// repository 的同一行锁事务内裁决，客户端无法提交金额或延长过期时间。
func (s *Service) ClaimVipDailyCoinRebate(ctx context.Context, command ledger.ClaimVipDailyCoinRebateCommand) (ledger.ClaimVipDailyCoinRebateReceipt, error) {
	command.AppCode = appcode.Normalize(command.AppCode)
	command.CommandID = strings.TrimSpace(command.CommandID)
	command.RebateID = strings.TrimSpace(command.RebateID)
	if command.CommandID == "" || command.UserID <= 0 || command.RebateID == "" {
		return ledger.ClaimVipDailyCoinRebateReceipt{}, xerr.New(xerr.InvalidArgument, "vip daily coin rebate claim command is incomplete")
	}
	if len(command.CommandID) > 128 || len(command.RebateID) > 96 {
		return ledger.ClaimVipDailyCoinRebateReceipt{}, xerr.New(xerr.InvalidArgument, "vip daily coin rebate claim command is invalid")
	}
	if s.repository == nil {
		return ledger.ClaimVipDailyCoinRebateReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.NowMS = s.now().UTC().UnixMilli()
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.ClaimVipDailyCoinRebate(ctx, command)
}
