package com.red.circle.other.app.service;

import com.red.circle.common.business.core.enums.ReceiptType;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.app.dto.clientobject.BdSalarySettlementCO;
import com.red.circle.other.app.dto.clientobject.BdTeamStatisticsCO;
import com.red.circle.other.app.dto.clientobject.SalaryCalcResult;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.bd.detail.BdTeamMemberDetail;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget;
import com.red.circle.other.infra.database.mongo.service.team.TeamBillCycleUtils;
import com.red.circle.other.infra.enums.BdPolicyType;
import com.red.circle.other.infra.enums.BdSettlementStatus;
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalaryPolicy;
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalarySettlementRecord;
import com.red.circle.other.infra.database.mongo.service.bd.BdSalaryPolicyService;
import com.red.circle.other.infra.database.mongo.service.bd.BdSalarySettlementRecordService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService;
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentTeam;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentTeamService;
import com.red.circle.other.inner.enums.team.TeamSalaryStatisticsCO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.order.inner.endpoint.api.InAppPurchaseDetailsClientApi;
import com.red.circle.order.inner.model.dto.inapp.BatchUserRechargeStatisticsDTO;
import com.red.circle.wallet.inner.endpoint.bank.UserBankBalanceClient;
import com.red.circle.wallet.inner.endpoint.bank.UserBankRunningWaterClient;
import com.red.circle.wallet.inner.endpoint.salary.UserSalaryAccountClient;
import com.red.circle.wallet.inner.model.cmd.SalaryIssueInnerCmd;
import com.red.circle.wallet.inner.model.cmd.UserBankBalanceIncrCmd;
import com.red.circle.wallet.inner.model.dto.UserBankRunningWaterDTO;
import com.red.circle.wallet.inner.model.enums.UserBankWaterEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * BD 工资结算服务实现.
 *
 * @author AI Assistant
 * @since 2025-10-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BdSalarySettlementServiceImpl implements BdSalarySettlementService {

    private final BusinessDevelopmentTeamService businessDevelopmentTeamService;
    private final TeamMemberTargetService teamMemberTargetService;
    private final BdSalaryPolicyService bdSalaryPolicyService;
    private final BdSalarySettlementRecordService bdSalarySettlementRecordService;
    private final InAppPurchaseDetailsClientApi inAppPurchaseDetailsClientApi;
    private final UserProfileGateway userProfileGateway;
    private final UserSalaryAccountClient userSalaryAccountClient;


    @Override
    public void processAllBdSettlement(Integer billBelong, String billTitle) {
        log.warn("开始处理所有 BD 工资结算，结算周期：{}", billBelong);

        // 查询所有 BD
        List<BusinessDevelopmentTeam> allBdTeams = businessDevelopmentTeamService.listAll();

        if (CollectionUtils.isEmpty(allBdTeams)) {
            log.warn("没有找到任何 BD 数据");
            return;
        }

        // 按 BD 用户 ID 分组（去重）
        Map<Long, List<BusinessDevelopmentTeam>> bdGroupMap = allBdTeams.stream()
                .collect(Collectors.groupingBy(BusinessDevelopmentTeam::getUserId));

        log.warn("共找到 {} 个 BD", bdGroupMap.size());

        int successCount = 0;
        int failCount = 0;

        // 遍历每个 BD 进行结算
        for (Long bdUserId : bdGroupMap.keySet()) {
            try {
                processSingleBdSettlement(bdUserId, billBelong, billTitle);
                successCount++;
            } catch (Exception e) {
                log.error("BD {} 工资结算失败", bdUserId, e);
                failCount++;
            }
        }

        log.warn("BD 工资结算完成，成功：{}，失败：{}", successCount, failCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BdSalarySettlementCO processSingleBdSettlement(Long bdUserId, Integer billBelong, String billTitle) {
        log.info("开始处理 BD {} 的工资结算", bdUserId);

        // 1. 生成幂等业务号
        String bizNo = generateBizNo(bdUserId, billBelong);

        // 2. 幂等性检查
        if (bdSalarySettlementRecordService.existsByBizNo(bizNo)) {
            log.warn("BD {} 在周期 {} 已经结算过，跳过", bdUserId, billBelong);
            BdSalarySettlementRecord existingRecord = bdSalarySettlementRecordService.getByBizNo(bizNo);
            return convertToCO(existingRecord);
        }

        // 3. 统计 BD 团队数据
        BdTeamStatisticsCO teamStatistics = statisticsBdTeam(bdUserId, billBelong);

        // 4. 收集团队成员明细数据
        List<BdTeamMemberDetail> memberDetails = collectTeamMemberDetails(bdUserId, billBelong, teamStatistics);

        // 5. 匹配政策并计算工资
        BdSalarySettlementRecord record = calculateSalary(bdUserId, billBelong, billTitle, teamStatistics, bizNo);
        record.setMemberDetails(memberDetails);

        // 6. 保存结算记录
        bdSalarySettlementRecordService.create(record);

        // 7. 如果工资大于 0，则发放工资
        if (record.getSettlementSalary() != null && record.getSettlementSalary().compareTo(BigDecimal.ZERO) > 0) {
            try {
                // 调用钱包服务发放工资
                issueSalary(bdUserId, record);
                
                log.info("BD {} 工资发放成功，金额：{} USD", bdUserId, record.getSettlementSalary());
            } catch (Exception e) {
                log.error("BD {} 工资发放失败", bdUserId, e);
                bdSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.FAILED, e.getMessage());
                record.setStatus(BdSettlementStatus.FAILED);
                record.setFailureReason(e.getMessage());
                throw e;
            }
        } else {
            log.info("BD {} 本周期未达到结算标准，无工资发放", bdUserId);
        }
        // 更新状态为成功
        bdSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.SUCCESS, null);
        record.setStatus(BdSettlementStatus.SUCCESS);

        return convertToCO(record);
    }

    /**
     * 收集团队成员明细数据.
     */
    private List<BdTeamMemberDetail> collectTeamMemberDetails(Long bdUserId, Integer billBelong, 
                                                               BdTeamStatisticsCO teamStatistics) {
        List<BdTeamMemberDetail> memberDetails = new ArrayList<>();
        
        // 查询 BD 下的所有 Agent 团队
        List<BusinessDevelopmentTeam> bdTeams = businessDevelopmentTeamService.listByBdUserId(bdUserId);
        
        if (CollectionUtils.isEmpty(bdTeams)) {
            return memberDetails;
        }
        
        // 收集所有用户ID
        Set<Long> allUserIds = new HashSet<>();
        Map<Long, Integer> userHostCountMap = new HashMap<>();
        Map<Long, BigDecimal> userSalaryMap = new HashMap<>();
        
        // 遍历每个团队，统计每个用户的数据
        for (BusinessDevelopmentTeam bdTeam : bdTeams) {
            Long agentId = bdTeam.getAgentId();
            allUserIds.add(agentId);

            // 查询该团队的成员目标记录
            List<TeamMemberTarget> memberTargets =
                teamMemberTargetService.listByBillBelong(bdTeam.getTeamId(), billBelong);
            
            if (CollectionUtils.isEmpty(memberTargets)) {
                continue;
            }

            // 统计每个用户的数据
            for (TeamMemberTarget target : memberTargets) {
                // 统计 Host 数量
                userHostCountMap.merge(agentId, 1, Integer::sum);
                
                // 统计工资（从结算结果中获取）
                if (target.getSettlementResult() != null && target.getSettlementResult().getTotalSalary() != null) {
                    BigDecimal salary = target.getSettlementResult().getTotalSalary();
                    userSalaryMap.merge(agentId, salary, BigDecimal::add);
                }
            }
        }
        
        if (CollectionUtils.isEmpty(allUserIds)) {
            return memberDetails;
        }
        
        // 批量查询用户信息
        Map<Long, UserProfile> userProfileMap = userProfileGateway.mapByUserIds(allUserIds);

        // 计算结算周期的开始和结束时间
        int year, month;

        if (billBelong > 999999) {
          // 8位格式：20251016
          year = billBelong / 10000;
          month = (billBelong / 100) % 100;
        } else {
          // 6位格式：202510
          year = billBelong / 100;
          month = billBelong % 100;
        }
        LocalDateTime startTime = java.time.LocalDateTime.of(year, month, 1, 0, 0, 0);
        LocalDateTime endTime = startTime.plusMonths(1).minusSeconds(1);

        // 批量查询用户充值统计
        Map<Long, BigDecimal> userRechargeMap = new HashMap<>();
        try {
            ResultResponse<List<BatchUserRechargeStatisticsDTO>> response =
                inAppPurchaseDetailsClientApi.batchUserRechargeStatistics(
                    new ArrayList<>(allUserIds),
                    SysOriginPlatformEnum.LIKEI.name(),
                    startTime,
                    endTime
                );
            
            if (response != null && response.getStatus() && !CollectionUtils.isEmpty(response.getBody())) {
                response.getBody().forEach(dto -> {
                    if (dto.getTotalAmount() != null) {
                        userRechargeMap.put(dto.getUserId(), dto.getTotalAmount());
                    }
                });
            }
        } catch (Exception e) {
            log.error("查询用户充值统计失败", e);
        }
        
        // 组装成员明细数据
        for (Long userId : allUserIds) {
            BdTeamMemberDetail detail = new BdTeamMemberDetail();
            detail.setUserId(userId);
            
            // 设置用户信息
            UserProfile userProfile = userProfileMap.get(userId);
            if (userProfile != null) {
                detail.setUserName(userProfile.getUserNickname());
                detail.setUserAvatar(userProfile.getUserAvatar());
                detail.setUserAccount(userProfile.getAccount());
            }
            
            // 设置工资
            BigDecimal salary = userSalaryMap.getOrDefault(userId, BigDecimal.ZERO);
            detail.setSalary(salary.setScale(2, RoundingMode.DOWN));
            
            // 设置充值
            BigDecimal recharge = userRechargeMap.getOrDefault(userId, BigDecimal.ZERO);
            detail.setRecharge(recharge.setScale(2, RoundingMode.DOWN));
            
            // 设置 Host 数量
            detail.setHostCount(userHostCountMap.getOrDefault(userId, 0));
            
            memberDetails.add(detail);
        }
        
        // 按工资降序排列
        memberDetails.sort((a, b) -> b.getSalary().compareTo(a.getSalary()));
        
        return memberDetails;
    }

    /**
     * 统计 BD 的团队数据.
     */
    private BdTeamStatisticsCO statisticsBdTeam(Long bdUserId, Integer billBelong) {
        // 查询 BD 下的所有 Agent 团队
        List<BusinessDevelopmentTeam> bdTeams = businessDevelopmentTeamService.listByBdUserId(bdUserId);
        
        BdTeamStatisticsCO statistics = new BdTeamStatisticsCO();
        statistics.setBdUserId(bdUserId);
        statistics.setAgencyNumber(bdTeams.size());

        if (CollectionUtils.isEmpty(bdTeams)) {
            statistics.setTeamSalaryAmount(BigDecimal.ZERO);
            statistics.setTeamRechargeAmount(BigDecimal.ZERO);
            return statistics;
        }

        // 统计团队工资总和和收集所有用户ID
        BigDecimal totalSalary = BigDecimal.ZERO;
        List<Long> allUserIds = new ArrayList<>();
        
        for (BusinessDevelopmentTeam bdTeam : bdTeams) {
            // 从 TeamMemberTarget 统计该团队的工资和用户ID
            TeamSalaryStatisticsCO teamStatistics =
                teamMemberTargetService.statisticsTeamSalaryByTeamIdAndBillBelong(
                    bdTeam.getTeamId(), billBelong);
            
            totalSalary = totalSalary.add(teamStatistics.getTotalSalary());
            allUserIds.addAll(teamStatistics.getUserIds());
        }
        statistics.setTeamSalaryAmount(totalSalary.setScale(2, RoundingMode.DOWN));

        // 统计团队充值总和（从订单服务统计）
        BigDecimal totalRecharge = statisticsTeamRecharge(allUserIds, billBelong);
        statistics.setTeamRechargeAmount(totalRecharge.setScale(2, RoundingMode.DOWN));

        return statistics;
    }

    /**
     * 统计团队充值总和.
     *
     * @param userIds 用户ID列表
     * @param billBelong 结算周期（格式：yyyyMM）
     * @return 充值总金额（美元）
     */
    private BigDecimal statisticsTeamRecharge(List<Long> userIds, Integer billBelong) {
        if (CollectionUtils.isEmpty(userIds)) {
            return BigDecimal.ZERO;
        }

        try {
            // 计算结算周期的开始和结束时间
            LocalDateTime startTime = TeamBillCycleUtils.getBillBelongStartTime(billBelong);
            LocalDateTime endTime = TeamBillCycleUtils.getBillBelongEndTime(billBelong);

            // 调用订单服务批量查询用户充值统计
            ResultResponse<List<BatchUserRechargeStatisticsDTO>> response =
                inAppPurchaseDetailsClientApi.batchUserRechargeStatistics(
                    userIds,
                    SysOriginPlatformEnum.LIKEI.name(),
                    startTime,
                    endTime
                );

            if (response == null || !response.getStatus() || CollectionUtils.isEmpty(response.getBody())) {
                log.warn("查询用户充值统计失败或无数据，userIds: {}, billBelong: {}", userIds.size(), billBelong);
                return BigDecimal.ZERO;
            }

            // 统计所有用户的充值总和
            BigDecimal totalRecharge = response.getBody().stream()
                .map(BatchUserRechargeStatisticsDTO::getTotalAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

            log.info("统计团队充值成功，用户数: {}, 结算周期: {}, 充值总额: {} USD", 
                     userIds.size(), billBelong, totalRecharge);

            return totalRecharge;

        } catch (Exception e) {
            log.error("统计团队充值失败，userIds: {}, billBelong: {}", userIds.size(), billBelong, e);
            return BigDecimal.ZERO;
        }
    }

    /**
     * 匹配政策并计算工资.
     */
    private BdSalarySettlementRecord calculateSalary(Long bdUserId, Integer billBelong, String billTitle,
                                                      BdTeamStatisticsCO teamStatistics, String bizNo) {
        BdSalarySettlementRecord record = new BdSalarySettlementRecord();
        record.setId(IdWorkerUtils.getIdStr());
        record.setTimeId(IdWorkerUtils.getId());
        record.setSysOrigin(SysOriginPlatformEnum.LIKEI.name());
        record.setBdUserId(bdUserId);
        record.setBillBelong(billBelong);
        record.setBillTitle(billTitle);
        record.setAgencyNumber(teamStatistics.getAgencyNumber());
        record.setTeamSalaryAmount(teamStatistics.getTeamSalaryAmount());
        record.setTeamRechargeAmount(teamStatistics.getTeamRechargeAmount());
        record.setBizNo(bizNo);
        record.setStatus(BdSettlementStatus.PENDING);

        // 获取所有启用的政策
        List<BdSalaryPolicy> salaryPolicies = bdSalaryPolicyService.listEnabledByType(BdPolicyType.TEAM_SALARY);
        List<BdSalaryPolicy> rechargePolicies = bdSalaryPolicyService.listEnabledByType(BdPolicyType.TEAM_RECHARGE);

        // 匹配政策1：Team Salary Policy
        SalaryCalcResult salaryResult = matchAndCalculate(salaryPolicies, teamStatistics.getAgencyNumber(),
                teamStatistics.getTeamSalaryAmount());

        // 匹配政策2：Team Recharge Policy
        SalaryCalcResult rechargeResult = matchAndCalculate(rechargePolicies, teamStatistics.getAgencyNumber(),
                teamStatistics.getTeamRechargeAmount());

        // 选择最高工资
        if (salaryResult.getSalary().compareTo(rechargeResult.getSalary()) >= 0) {
            record.setHitPolicyType(BdPolicyType.TEAM_SALARY);
            record.setHitLevel(salaryResult.getHitLevel());
            record.setCommissionRate(salaryResult.getCommissionRate());
            record.setSettlementSalary(salaryResult.getSalary());
        } else {
            record.setHitPolicyType(BdPolicyType.TEAM_RECHARGE);
            record.setHitLevel(rechargeResult.getHitLevel());
            record.setCommissionRate(rechargeResult.getCommissionRate());
            record.setSettlementSalary(rechargeResult.getSalary());
        }

        return record;
    }

    /**
     * 匹配政策并计算工资.
     */
    public static SalaryCalcResult matchAndCalculate(List<BdSalaryPolicy> policies, Integer agencyNumber,
                                                     BigDecimal teamAmount) {
        if (CollectionUtils.isEmpty(policies)) {
            return new SalaryCalcResult(BigDecimal.ZERO, 0, BigDecimal.ZERO);
        }

        // 按等级倒序排序，匹配最高等级
        policies.sort((p1, p2) -> p2.getLevel().compareTo(p1.getLevel()));

        for (BdSalaryPolicy policy : policies) {
            // 必须同时满足 Agent 数量和团队金额
            if (agencyNumber >= policy.getRequiredAgencyNumber()
                    && teamAmount.compareTo(policy.getRequiredTeamAmount()) >= 0) {

                // 计算工资：团队金额 * 提成比例
                BigDecimal salary = teamAmount.multiply(policy.getCommissionRate())
                        .divide(new BigDecimal("100"), 2, RoundingMode.DOWN);

                return new SalaryCalcResult(salary, policy.getLevel(), policy.getCommissionRate());
            }
        }

        return new SalaryCalcResult(BigDecimal.ZERO, 0, BigDecimal.ZERO);
    }

    /**
     * 发放工资到美元账户.
     */
    private void issueSalary(Long bdUserId, BdSalarySettlementRecord record) {
        SalaryIssueInnerCmd innerCmd = new SalaryIssueInnerCmd();
        innerCmd.setBillBelong(record.getBillBelong());
        innerCmd.setUserId(bdUserId);
        innerCmd.setSysOrigin(record.getSysOrigin());
        innerCmd.setSalaryType("BD_SALARY");
        innerCmd.setEventDesc("SALARY_BD");
        innerCmd.setAmount(record.getSettlementSalary());
        innerCmd.setTrackId(record.getId());
        innerCmd.setBdId(bdUserId);
        userSalaryAccountClient.issueSalary(innerCmd);
    }

    /**
     * 生成业务号（幂等性保证）.
     */
    private String generateBizNo(Long bdUserId, Integer billBelong) {
        return String.format("BD_SALARY_%d_%d", bdUserId, billBelong);
    }

    /**
     * 转换为 CO 对象.
     */
    private BdSalarySettlementCO convertToCO(BdSalarySettlementRecord record) {
        BdSalarySettlementCO co = new BdSalarySettlementCO();
        co.setBdUserId(record.getBdUserId());
        co.setBillBelong(record.getBillBelong());
        co.setBillTitle(record.getBillTitle());
        co.setAgencyNumber(record.getAgencyNumber());
        co.setTeamSalaryAmount(record.getTeamSalaryAmount());
        co.setTeamRechargeAmount(record.getTeamRechargeAmount());
        co.setHitPolicyType(record.getHitPolicyType().name());
        co.setHitLevel(record.getHitLevel());
        co.setCommissionRate(record.getCommissionRate());
        co.setSettlementSalary(record.getSettlementSalary());
        co.setStatus(record.getStatus().name());
        co.setFailureReason(record.getFailureReason());
        return co;
    }
}
