import com.red.circle.OtherServiceApplication;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.common.team.decay.ListMemberWorkDecay;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService;
import com.red.circle.other.inner.model.cmd.team.TeamMemberWorkQryCmd;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkDTO;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkDailyTargetDTO;
import com.red.circle.tool.core.date.TimestampUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.stream.Collectors;

@SpringBootTest(classes = OtherServiceApplication.class)
@RunWith(SpringRunner.class)
public class AnchorTargetTest {

    @Autowired
    private TeamMemberTargetService teamMemberTargetService;
    @Autowired
    private ListMemberWorkDecay listMemberWorkDecay;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserProfileGateway userProfileGateway;


    /**
     * 扣除主播目标
     */
    @Test
    public void AnchorTargetTest(){
        Long userId = 1987522531364773890L;
        Long deductValue = 300000L; // 要扣除的目标值

        TeamMemberWorkQryCmd cmd = new TeamMemberWorkQryCmd();
        cmd.setMemberUserId(userId);
        cmd.setSysOrigin("LIKEI");
        List<TeamMemberWorkDTO> execute = listMemberWorkDecay.execute(cmd);
        
        // 1. 筛选 billStatus = UNPAID 的数据
        List<TeamMemberWorkDTO> unpaidList = execute.stream()
                .filter(work -> "UNPAID".equals(work.getBillStatus()))
                .limit(1)
                .toList();
        
        System.out.println("未结算的工单数量: " + unpaidList.size());
        
        for (TeamMemberWorkDTO work : unpaidList) {
            // 2. 统计 dailyTargets 的 acceptGiftValue 的和
            Long totalAcceptGiftValue = work.getTarget().getDailyTargets().stream()
                    .mapToLong(TeamMemberWorkDailyTargetDTO::getAcceptGiftValue)
                    .sum();
            
            System.out.println("工单ID: " + work.getId() + ", 总收礼物价值: " + totalAcceptGiftValue);
            
            // 3. 检查目标值够不够扣
            if (totalAcceptGiftValue < deductValue) {
                System.out.println("目标值不足，无法扣除。需要: " + deductValue + ", 当前: " + totalAcceptGiftValue);
                continue;
            }
            
            // 4. 从第一天开始扣除
            Long remainingDeduct = deductValue;
            List<TeamMemberWorkDailyTargetDTO> dailyTargets = work.getTarget().getDailyTargets();
            boolean hasModified = false; // 标记是否有修改

            for (int i = 0; i < dailyTargets.size(); i++) {
                TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i);
                Long currentValue = dailyTarget.getAcceptGiftValue();

                if (remainingDeduct <= 0) {
                    break;
                }

                if (currentValue > 0) { // 只有当前值大于0时才可能修改
                    hasModified = true; // 标记为已修改

                    if (currentValue >= remainingDeduct) {
                        // 当前天的值足够扣除剩余部分
                        dailyTarget.setAcceptGiftValue(currentValue - remainingDeduct);
                        System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + remainingDeduct + ", 剩余: " + (currentValue - remainingDeduct));
                        remainingDeduct = 0L;
                    } else {
                        // 当前天的值不够，全部扣除
                        dailyTarget.setAcceptGiftValue(0L);
                        remainingDeduct -= currentValue;
                        System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + currentValue + ", 剩余需扣除: " + remainingDeduct);
                    }
                }
            }

            // 5. 只有当有修改时才更新 MongoDB
            if (hasModified) {
                updateTeamMemberTarget(work.getId(), dailyTargets);
                System.out.println("工单 " + work.getId() + " 扣除完成，已更新到MongoDB");
            } else {
                System.out.println("工单 " + work.getId() + " 无需修改，跳过更新");
            }
        }
    }

    /**
     * 批量扣除主播目标
     */
    @Test
    public void batchAnchorTargetDeduct() {
        Map<Long, Long> map = Map.ofEntries(
                Map.entry(22222L, 3750000L),
                Map.entry(8846195L, 1125000L),
                Map.entry(8846188L, 150000L),
                Map.entry(8846174L, 750000L),
                Map.entry(8846185L, 750000L),
                Map.entry(8848862L, 6000000L),
                Map.entry(8849422L, 300000L),
                Map.entry(8846353L, 300000L)
        );

        // 将account转换为userId并构建batchDeductMap
        Map<Long, Long> batchDeductMap = new HashMap<>();
        map.forEach((account, amount) -> {
            UserProfile userProfile = userProfileGateway.getByAccount("LIKEI", String.valueOf(account));
            if (Objects.nonNull(userProfile)) {
                batchDeductMap.put(userProfile.getId(), amount);
            } else {
                throw new RuntimeException("账号不存在:" + account);
            }
        });


        // 定义批量扣除的用户和金额列表
//        Map<Long, Long> batchDeductMap = new HashMap<>();
//        batchDeductMap.put(1957345312961527809L, 1L);
//        batchDeductMap.put(1989287471839113218L, 1L);
        // 可以继续添加更多用户...

        System.out.println("========== 开始批量扣除 ==========");
        System.out.println("批量扣除总数: " + batchDeductMap.size());
        System.out.println();

        // 统计数据
        int successCount = 0;  // 成功扣除的数量
        int failCount = 0;     // 失败的数量
        int skipCount = 0;     // 跳过的数量（目标值不足）
        long totalDeductValue = 0L;  // 总扣除金额
        List<String> failedUsers = new ArrayList<>();  // 失败的用户列表

        // 循环批量扣除
        for (Map.Entry<Long, Long> entry : batchDeductMap.entrySet()) {
            Long userId = entry.getKey();
            Long deductValue = entry.getValue();

            System.out.println("---------- 处理用户: " + userId + " ----------");
            System.out.println("扣除金额: " + deductValue);

            try {
                boolean result = deductSingleAnchorTarget(userId, deductValue);
                if (result) {
                    successCount++;
                    totalDeductValue += deductValue;
                    System.out.println("✓ 用户 " + userId + " 扣除成功");
                } else {
                    skipCount++;
                    System.out.println("⊘ 用户 " + userId + " 跳过（目标值不足或无未结算工单）");
                }
            } catch (Exception e) {
                failCount++;
                failedUsers.add(userId + " (错误: " + e.getMessage() + ")");
                System.out.println("✗ 用户 " + userId + " 扣除失败: " + e.getMessage());
                e.printStackTrace();
            }

            System.out.println();
        }

        // 打印统计结果
        System.out.println("========== 批量扣除完成 ==========");
        System.out.println("总处理数: " + batchDeductMap.size());
        System.out.println("成功数: " + successCount);
        System.out.println("跳过数: " + skipCount);
        System.out.println("失败数: " + failCount);
        System.out.println("总扣除金额: " + totalDeductValue);
        System.out.println("成功率: " + String.format("%.2f%%", (successCount * 100.0 / batchDeductMap.size())));

        if (!failedUsers.isEmpty()) {
            System.out.println("\n失败用户列表:");
            failedUsers.forEach(user -> System.out.println("  - " + user));
        }

        System.out.println("========================================");
    }

    /**
     * 单个主播目标扣除（从原方法提取出来）
     * @param userId 用户ID
     * @param deductValue 扣除金额
     * @return true-成功扣除, false-跳过（目标值不足或无未结算工单）
     */
    private boolean deductSingleAnchorTarget(Long userId, Long deductValue) {
        TeamMemberWorkQryCmd cmd = new TeamMemberWorkQryCmd();
        cmd.setMemberUserId(userId);
        cmd.setSysOrigin("LIKEI");
        List<TeamMemberWorkDTO> execute = listMemberWorkDecay.execute(cmd);

        // 1. 筛选 billStatus = UNPAID 的数据
        List<TeamMemberWorkDTO> unpaidList = execute.stream()
                .filter(work -> "UNPAID".equals(work.getBillStatus()))
                .limit(1)
                .toList();

        System.out.println("未结算的工单数量: " + unpaidList.size());

        if (unpaidList.isEmpty()) {
            return false;
        }

        for (TeamMemberWorkDTO work : unpaidList) {
            // 2. 统计 dailyTargets 的 acceptGiftValue 的和
            Long totalAcceptGiftValue = work.getTarget().getDailyTargets().stream()
                    .mapToLong(TeamMemberWorkDailyTargetDTO::getAcceptGiftValue)
                    .sum();

            System.out.println("工单ID: " + work.getId() + ", 总收礼物价值: " + totalAcceptGiftValue);

            // 3. 检查目标值够不够扣
            if (totalAcceptGiftValue < deductValue) {
                System.out.println("目标值不足，无法扣除。需要: " + deductValue + ", 当前: " + totalAcceptGiftValue);
                return false;
            }

            // 4. 从第一天开始扣除
            Long remainingDeduct = deductValue;
            List<TeamMemberWorkDailyTargetDTO> dailyTargets = work.getTarget().getDailyTargets();
            boolean hasModified = false; // 标记是否有修改

            for (int i = 0; i < dailyTargets.size(); i++) {
                TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i);
                Long currentValue = dailyTarget.getAcceptGiftValue();

                if (remainingDeduct <= 0) {
                    break;
                }

                if (currentValue > 0) { // 只有当前值大于0时才可能修改
                    hasModified = true; // 标记为已修改

                    if (currentValue >= remainingDeduct) {
                        // 当前天的值足够扣除剩余部分
                        dailyTarget.setAcceptGiftValue(currentValue - remainingDeduct);
                        System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + remainingDeduct + ", 剩余: " + (currentValue - remainingDeduct));
                        remainingDeduct = 0L;
                    } else {
                        // 当前天的值不够，全部扣除
                        dailyTarget.setAcceptGiftValue(0L);
                        remainingDeduct -= currentValue;
                        System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + currentValue + ", 剩余需扣除: " + remainingDeduct);
                    }
                }
            }

            // 5. 只有当有修改时才更新 MongoDB
            if (hasModified) {
                updateTeamMemberTarget(work.getId(), dailyTargets);
                System.out.println("工单 " + work.getId() + " 扣除完成，已更新到MongoDB");
                return true;
            } else {
                System.out.println("工单 " + work.getId() + " 无需修改，跳过更新");
                return false;
            }
        }

        return false;
    }

    /**
     * 更新 MongoDB 中的 TeamMemberTarget
     * @param timeId 工单ID
     * @param dailyTargets 更新后的每日目标列表
     */
    private void updateTeamMemberTarget(Long timeId, List<TeamMemberWorkDailyTargetDTO> dailyTargets) {
        Query query = new Query(Criteria.where("timeId").is(timeId));

        // 更新 target.dailyTargets 数组
        for (int i = 0; i < dailyTargets.size(); i++) {
            TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i);

            mongoTemplate.updateFirst(query,
                    new Update()
                            .set("updateTime", TimestampUtils.now())
                            .set("dailyTargets.$[i].acceptGiftValue", dailyTarget.getAcceptGiftValue())
                            .set("dailyTargets.$[i].updateTime", TimestampUtils.now())
                            .filterArray(Criteria.where("i.dateNumber").is(dailyTarget.getDateNumber())),
                    TeamMemberTarget.class);
        }
    }

}
