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

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.other.app.dto.clientobject.BdLeaderSalarySettlementCO;
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.BdLeaderTeamMemberDetail;
import com.red.circle.other.infra.database.rds.entity.sys.Administrator;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.infra.enums.BdSettlementStatus;
import com.red.circle.other.infra.database.mongo.entity.bd.BdLeaderSalaryPolicy;
import com.red.circle.other.infra.database.mongo.entity.bd.BdLeaderSalarySettlementRecord;
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalarySettlementRecord;
import com.red.circle.other.infra.database.mongo.service.bd.BdLeaderSalaryPolicyService;
import com.red.circle.other.infra.database.mongo.service.bd.BdLeaderSalarySettlementRecordService;
import com.red.circle.other.infra.database.mongo.service.bd.BdSalarySettlementRecordService;
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBaseInfo;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentTeamService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.wallet.inner.endpoint.bank.UserBankBalanceClient;
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.dto.SalaryRunningWaterDTO;
import com.red.circle.wallet.inner.model.enums.SalaryType;
import com.red.circle.wallet.inner.model.enums.SalaryEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

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

    private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService;
    private final BdSalarySettlementRecordService bdSalarySettlementRecordService;
    private final BdLeaderSalaryPolicyService bdLeaderSalaryPolicyService;
    private final BdLeaderSalarySettlementRecordService bdLeaderSalarySettlementRecordService;
    private final AdministratorService administratorService;
    private final UserSalaryAccountClient userSalaryAccountClient;
    private final UserProfileGateway userProfileGateway;

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

        // 查询所有 BD Leader
        List<BusinessDevelopmentBaseInfo> allBdLeaders = businessDevelopmentBaseInfoService.listAll();
        
        if (CollectionUtils.isEmpty(allBdLeaders)) {
            log.warn("没有找到任何 BD Leader 数据");
            return;
        }

        Set<Long> adminUserIds = getAdminUserIds();

        // 按 BD Leader 用户 ID 分组（去重），并过滤掉管理员
        Map<Long, List<BusinessDevelopmentBaseInfo>> bdLeaderGroupMap = allBdLeaders.stream()
                .filter(info -> info.getBdLeadUserId() != null)
                .collect(Collectors.groupingBy(BusinessDevelopmentBaseInfo::getBdLeadUserId));

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

        int successCount = 0;
        int failCount = 0;

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

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

    private Set<Long> getAdminUserIds() {
        List<Administrator> administrators = administratorService.listAllAdmins();
        return administrators.stream()
                .map(Administrator::getUserId)
                .collect(Collectors.toSet());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BdLeaderSalarySettlementCO processSingleBdLeaderSettlement(Long bdLeaderUserId, Integer billBelong, String billTitle, Set<Long> adminUserIds) {
        log.info("开始处理 BD Leader {} 的工资结算", bdLeaderUserId);

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

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

        // 3. 统计 BD Leader 的团队数据
        List<Long> bdUserIds = businessDevelopmentBaseInfoService.listBdUserIdsByLeaderId(bdLeaderUserId);
        
        BdLeaderSalarySettlementRecord record = new BdLeaderSalarySettlementRecord();
        record.setId(IdWorkerUtils.getIdStr());
        record.setTimeId(IdWorkerUtils.getId());
        record.setSysOrigin(SysOriginPlatformEnum.LIKEI.name());
        record.setBdLeaderUserId(bdLeaderUserId);
        record.setBillBelong(billBelong);
        record.setBillTitle(billTitle);
        record.setBdNumber(bdUserIds.size());
        record.setBizNo(bizNo);
        record.setStatus(BdSettlementStatus.PENDING);

        // 4. 统计所有 BD 的工资总和并收集成员明细
        List<BdLeaderTeamMemberDetail> memberDetails = new ArrayList<>();
        BigDecimal totalBdSalary = BigDecimal.ZERO;

        for (Long bdUserId : bdUserIds) {
            BdSalarySettlementRecord bdRecord = bdSalarySettlementRecordService.getByUserIdAndBillBelong(bdUserId, billBelong);
            
            if (bdRecord != null) {
                // 统计工资
                if (bdRecord.getTeamSalaryAmount() != null) {
                    totalBdSalary = totalBdSalary.add(bdRecord.getTeamSalaryAmount());
                }
                
                // 收集成员明细
                BdLeaderTeamMemberDetail detail = new BdLeaderTeamMemberDetail();
                detail.setBdUserId(bdUserId);
                detail.setSalary(bdRecord.getSettlementSalary() != null ? 
                    bdRecord.getSettlementSalary().setScale(2, RoundingMode.DOWN) : BigDecimal.ZERO);
                detail.setAgencyCount(bdRecord.getAgencyNumber() != null ? bdRecord.getAgencyNumber() : 0);
                
                memberDetails.add(detail);
            } else {
                BdLeaderTeamMemberDetail detail = new BdLeaderTeamMemberDetail();
                detail.setBdUserId(bdUserId);
                detail.setSalary(BigDecimal.ZERO);
                detail.setAgencyCount(0);
                memberDetails.add(detail);
            }
        }
        
        record.setTeamSalaryAmount(totalBdSalary.setScale(2, RoundingMode.DOWN));
        
        // 批量查询 BD 用户信息
        if (!CollectionUtils.isEmpty(memberDetails)) {
            Set<Long> bdUserIdSet = new HashSet<>(bdUserIds);
            Map<Long, UserProfile> userProfileMap = userProfileGateway.mapByUserIds(bdUserIdSet);

            for (BdLeaderTeamMemberDetail detail : memberDetails) {
                UserProfile userProfile = userProfileMap.get(detail.getBdUserId());
                if (userProfile != null) {
                    detail.setBdUserName(userProfile.getUserNickname());
                    detail.setBdUserAvatar(userProfile.getUserAvatar());
                    detail.setBdUserAccount(userProfile.getAccount());
                }
            }
            
            // 按工资降序排列
            memberDetails.sort((a, b) -> b.getSalary().compareTo(a.getSalary()));
        }
        
        record.setMemberDetails(memberDetails);

        // 5. 匹配政策并计算工资
        calculateLeaderSalary(record);

        // 6. 保存结算记录
        record.setIsAdmin(adminUserIds != null && adminUserIds.contains(bdLeaderUserId));
        bdLeaderSalarySettlementRecordService.create(record);

        // 7. 如果工资大于 0，则发放工资
        if (record.getSettlementSalary() != null &&
                record.getSettlementSalary().compareTo(BigDecimal.ZERO) > 0 &&
                !Boolean.TRUE.equals(record.getIsAdmin())) {
            try {
                // 调用钱包服务发放工资
                issueSalary(bdLeaderUserId, record);

            } catch (Exception e) {
                log.error("BD Leader {} 工资发放失败", bdLeaderUserId, e);
                bdLeaderSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.FAILED, e.getMessage());
                record.setStatus(BdSettlementStatus.FAILED);
                record.setFailureReason(e.getMessage());
                throw e;
            }
        } else {
            log.info("BD Leader {} 本周期未达到结算标准，无工资发放", bdLeaderUserId);
        }
        // 更新状态为成功
        bdLeaderSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.SUCCESS, null);
        record.setStatus(BdSettlementStatus.SUCCESS);

        return convertToCO(record);
    }

    /**
     * 匹配政策并计算 BD Leader 工资.
     */
    private void calculateLeaderSalary(BdLeaderSalarySettlementRecord record) {
        // 获取所有启用的政策
        List<BdLeaderSalaryPolicy> policies = bdLeaderSalaryPolicyService.listEnabled();
        
        if (CollectionUtils.isEmpty(policies)) {
            record.setSettlementSalary(BigDecimal.ZERO);
            return;
        }

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

        for (BdLeaderSalaryPolicy policy : policies) {
            // 必须同时满足 BD 数量和团队工资
            if (record.getBdNumber() >= policy.getRequiredBdNumber()
                    && record.getTeamSalaryAmount().compareTo(policy.getRequiredTeamSalary()) >= 0) {
                
                record.setHitLevel(policy.getLevel());
                record.setBasicSalary(policy.getBasicSalary());
                record.setRewardAmount(policy.getRewardAmount());
                
                // 计算最终工资：Basic Salary + Reward Amount（如果满足奖励条件）
                BigDecimal finalSalary = policy.getBasicSalary();
                
                // 检查是否满足奖励条件（本周期有新增 BD）
                boolean rewardEligible = checkRewardEligibility(record.getBdLeaderUserId(), record.getBillBelong());
                record.setRewardEligible(rewardEligible);
                
                if (rewardEligible && policy.getRewardAmount() != null) {
                    finalSalary = finalSalary.add(policy.getRewardAmount());
                }
                
                record.setSettlementSalary(finalSalary.setScale(2, RoundingMode.DOWN));
                return;
            }
        }

        // 未匹配到任何政策
        record.setSettlementSalary(BigDecimal.ZERO);
    }

    /**
     * 检查是否满足奖励条件（本周期是否有新增 BD）.
     */
    private boolean checkRewardEligibility(Long bdLeaderUserId, Integer billBelong) {
        // TODO: 实现逻辑 - 检查本周期是否有新增 BD
        // 目前简化处理：假设只要有 BD 就满足条件
//        List<Long> bdUserIds = businessDevelopmentBaseInfoService.listBdUserIdsByLeaderId(bdLeaderUserId);
//        return !CollectionUtils.isEmpty(bdUserIds);
        return false;
    }

    /**
     * 发放工资到美元账户.
     */
    private void issueSalary(Long bdLeaderUserId, BdLeaderSalarySettlementRecord record) {
        String bizNo = record.getBizNo();

        SalaryRunningWaterDTO runningWaterDTO = userSalaryAccountClient.existRunningWater(bizNo).getBody();
        if (runningWaterDTO != null) {
            return;
        }

        SalaryIssueInnerCmd innerCmd = new SalaryIssueInnerCmd();
        innerCmd.setBillBelong(record.getBillBelong());
        innerCmd.setUserId(bdLeaderUserId);
        innerCmd.setSysOrigin(record.getSysOrigin());
        innerCmd.setSalaryType(SalaryType.BD_LEADER_SALARY.getCode());
        innerCmd.setEventDesc(SalaryEvent.SALARY_BD_LEADER.getCode());
        innerCmd.setAmount(record.getSettlementSalary());
        innerCmd.setTrackId(record.getBizNo());
        innerCmd.setBdId(bdLeaderUserId);
        userSalaryAccountClient.issueSalary(innerCmd);

        log.info("BD Leader {} 工资发放成功，金额：{} USD", bdLeaderUserId, record.getSettlementSalary());
    }

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

    /**
     * 转换为 CO 对象.
     */
    private BdLeaderSalarySettlementCO convertToCO(BdLeaderSalarySettlementRecord record) {
        BdLeaderSalarySettlementCO co = new BdLeaderSalarySettlementCO();
        co.setBdLeaderUserId(record.getBdLeaderUserId());
        co.setBillBelong(record.getBillBelong());
        co.setBillTitle(record.getBillTitle());
        co.setBdNumber(record.getBdNumber());
        co.setTeamSalaryAmount(record.getTeamSalaryAmount());
        co.setHitLevel(record.getHitLevel());
        co.setBasicSalary(record.getBasicSalary());
        co.setRewardAmount(record.getRewardAmount());
        co.setRewardEligible(record.getRewardEligible());
        co.setNewRechargeAgentCount(record.getNewRechargeAgentCount());
        co.setSettlementSalary(record.getSettlementSalary());
        co.setStatus(record.getStatus().name());
        co.setFailureReason(record.getFailureReason());
        return co;
    }
}
