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

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.app.command.bd.query.BdTeamSummaryQryExe;
import com.red.circle.other.app.dto.clientobject.AdminSalarySettlementCO;
import com.red.circle.other.app.dto.clientobject.BdTeamSummaryCO;
import com.red.circle.other.app.dto.h5.RechargeSummaryVO;
import com.red.circle.other.app.service.recharge.RechargeUserService;
import com.red.circle.other.infra.database.mongo.entity.bd.AdminSalaryPolicy;
import com.red.circle.other.infra.database.mongo.entity.bd.AdminSalarySettlementRecord;
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.AdminSalaryPolicyService;
import com.red.circle.other.infra.database.mongo.service.bd.AdminSalarySettlementRecordService;
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.sys.Administrator;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.infra.enums.AdminPolicyType;
import com.red.circle.other.infra.enums.BdSettlementStatus;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
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.SalaryRunningWaterQueryInnerCmd;
import com.red.circle.wallet.inner.model.dto.SalaryRunningWaterDTO;
import com.red.circle.wallet.inner.model.enums.SalaryEvent;
import com.red.circle.wallet.inner.model.enums.SalaryType;
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.util.List;

/**
 * 管理员工资结算服务实现.
 *
 * @author AI Assistant
 * @since 2025-12-13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminSalarySettlementServiceImpl implements AdminSalarySettlementService {

    private final AdminSalaryPolicyService adminSalaryPolicyService;
    private final AdminSalarySettlementRecordService adminSalarySettlementRecordService;
    private final BdSalarySettlementRecordService bdSalarySettlementRecordService;
    private final BdLeaderSalarySettlementRecordService bdLeaderSalarySettlementRecordService;
    private final RechargeUserService rechargeUserService;
    private final UserSalaryAccountClient userSalaryAccountClient;
    private final AdministratorService administratorService;

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

        List<Administrator> administrators = administratorService.listAllAdmins();
        List<Long> adminUserIds = administrators.stream().map(Administrator::getUserId).toList();

        if (CollectionUtils.isEmpty(adminUserIds)) {
            log.warn("没有找到任何管理员数据");
            return;
        }

        log.warn("共找到 {} 个管理员", adminUserIds.size());

        int successCount = 0;
        int failCount = 0;

        for (Long adminUserId : adminUserIds) {
            try {
                processSingleAdminSettlement(adminUserId, billBelong, billTitle);
                successCount++;
            } catch (Exception e) {
                log.error("管理员 {} 工资结算失败", adminUserId, e);
                failCount++;
            }
        }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AdminSalarySettlementCO processSingleAdminSettlement(Long adminUserId, Integer billBelong, String billTitle) {
        log.info("开始处理管理员 {} 的工资结算", adminUserId);

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

        // 2. 幂等性检查
        if (adminSalarySettlementRecordService.existsByBizNo(bizNo)) {
            log.warn("管理员 {} 在周期 {} 已经结算过，跳过", adminUserId, billBelong);
            AdminSalarySettlementRecord existingRecord = adminSalarySettlementRecordService.getByBizNo(bizNo);
            return convertToCO(existingRecord);
        }

        // 3. 初始化结算记录
        AdminSalarySettlementRecord record = new AdminSalarySettlementRecord();
        record.setId(IdWorkerUtils.getIdStr());
        record.setTimeId(IdWorkerUtils.getId());
        record.setSysOrigin(SysOriginPlatformEnum.LIKEI.name());
        record.setAdminUserId(adminUserId);
        record.setBillBelong(billBelong);
        record.setBillTitle(billTitle);
        record.setBizNo(bizNo);
        record.setStatus(BdSettlementStatus.PENDING);

        // 4. 计算各个政策的工资
        try {
            // 4.1 RECHARGE_AGENT 政策
            calculateRechargeAgentPolicy(adminUserId, record);

            // 4.2 BD_LEADER 政策
            calculateBdLeaderPolicy(adminUserId, billBelong, record);

            // 4.3 BD_TEAM_SALARY 和 BD_TEAM_RECHARGE 政策（取最高值）
            calculateBdTeamPolicies(adminUserId, billBelong, record);

            // 4.4 计算总工资
            BigDecimal totalSalary = BigDecimal.ZERO;
            if (record.getRechargeAgentSalary() != null) {
                totalSalary = totalSalary.add(record.getRechargeAgentSalary());
            }
            if (record.getBdLeaderSalary() != null) {
                totalSalary = totalSalary.add(record.getBdLeaderSalary());
            }
            if (record.getBdPolicyFinalSalary() != null) {
                totalSalary = totalSalary.add(record.getBdPolicyFinalSalary());
            }
            record.setTotalSalary(totalSalary.setScale(2, RoundingMode.DOWN));

        } catch (Exception e) {
            log.error("管理员 {} 工资计算失败", adminUserId, e);
            record.setStatus(BdSettlementStatus.FAILED);
            record.setFailureReason(e.getMessage());
            adminSalarySettlementRecordService.create(record);
            throw e;
        }

        // 5. 保存结算记录
        adminSalarySettlementRecordService.create(record);

        // 6. 如果工资大于 0，则发放工资
        if (record.getTotalSalary().compareTo(BigDecimal.ZERO) > 0) {
            try {
                issueSalary(adminUserId, record);

            } catch (Exception e) {
                log.error("管理员 {} 工资发放失败", adminUserId, e);
                adminSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.FAILED, e.getMessage());
                record.setStatus(BdSettlementStatus.FAILED);
                record.setFailureReason(e.getMessage());
                throw e;
            }
        } else {
            log.info("管理员 {} 本周期未达到结算标准，无工资发放", adminUserId);
        }

        // 7. 更新状态为成功
        adminSalarySettlementRecordService.updateStatus(record.getId(), BdSettlementStatus.SUCCESS, null);
        record.setStatus(BdSettlementStatus.SUCCESS);

        return convertToCO(record);
    }

    /**
     * 计算 RECHARGE_AGENT 政策工资.
     */
    private void calculateRechargeAgentPolicy(Long adminUserId, AdminSalarySettlementRecord record) {
        // 构建命令对象
        AppExtCommand cmd = new AppExtCommand();
        cmd.setReqUserId(adminUserId);

        // 获取充值汇总数据
        RechargeSummaryVO rechargeSummary = rechargeUserService.getRechargeSummary(cmd);

        if (rechargeSummary == null || rechargeSummary.getCurrentMonthRecharge() == null) {
            record.setRechargeAgentAmount(BigDecimal.ZERO);
            record.setRechargeAgentSalary(BigDecimal.ZERO);
            return;
        }

        BigDecimal rechargeAmount = rechargeSummary.getCurrentMonthRecharge();
        record.setRechargeAgentAmount(rechargeAmount.setScale(2, RoundingMode.DOWN));

        // 查询 RECHARGE_AGENT 政策
        List<AdminSalaryPolicy> policies = adminSalaryPolicyService.listEnabledByType(
                AdminPolicyType.RECHARGE_AGENT.getCode());

        if (CollectionUtils.isEmpty(policies)) {
            record.setRechargeAgentSalary(BigDecimal.ZERO);
            return;
        }

        // 按充值金额倒序匹配
        policies.sort((p1, p2) -> p2.getRequiredCoinSellerRecharge().compareTo(p1.getRequiredCoinSellerRecharge()));

        for (AdminSalaryPolicy policy : policies) {
            if (rechargeAmount.compareTo(policy.getRequiredCoinSellerRecharge()) >= 0) {
                // 计算工资：充值金额 × 百分比
                BigDecimal salary = rechargeAmount.multiply(policy.getAdminPercentage())
                        .divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
                record.setRechargeAgentSalary(salary);
                record.setRechargeAgentPercentage(policy.getAdminPercentage());
                return;
            }
        }

        record.setRechargeAgentSalary(BigDecimal.ZERO);
    }

    /**
     * 计算 BD_LEADER 政策工资.
     */
    private void calculateBdLeaderPolicy(Long adminUserId, Integer billBelong, AdminSalarySettlementRecord record) {
        // 查询 BD Leader 团队数据
        BdLeaderSalarySettlementRecord bdLeaderSalarySettlementRecord = bdLeaderSalarySettlementRecordService.getByUserIdAndBillBelong(adminUserId, billBelong);

        if (bdLeaderSalarySettlementRecord == null) {
            record.setBdLeaderTeamSalary(BigDecimal.ZERO);
            record.setBdLeaderSalary(BigDecimal.ZERO);
            return;
        }

        BigDecimal teamSalary = bdLeaderSalarySettlementRecord.getTeamSalaryAmount();
        record.setBdLeaderTeamSalary(teamSalary);

        // 查询 BD_LEADER 政策
        List<AdminSalaryPolicy> policies = adminSalaryPolicyService.listEnabledByType(
                AdminPolicyType.BD_LEADER.getCode());

        if (CollectionUtils.isEmpty(policies)) {
            record.setBdLeaderSalary(BigDecimal.ZERO);
            return;
        }

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

        for (AdminSalaryPolicy policy : policies) {
            if (teamSalary.compareTo(policy.getRequiredTeamSalary()) >= 0) {
                // 工资 = Basic Salary
                BigDecimal salary = policy.getBasicSalary();
                if (policy.getRewardAmount() != null) {
//                    salary = salary.add(policy.getRewardAmount());
                }
                record.setBdLeaderSalary(salary.setScale(2, RoundingMode.DOWN));
                record.setBdLeaderHitLevel(policy.getLevel());
                record.setBdLeaderBasicSalary(policy.getBasicSalary());
                record.setBdLeaderRewardAmount(policy.getRewardAmount());
                return;
            }
        }

        record.setBdLeaderSalary(BigDecimal.ZERO);
    }

    /**
     * 计算 BD_TEAM_SALARY 和 BD_TEAM_RECHARGE 政策工资（取最高值）.
     */
    private void calculateBdTeamPolicies(Long adminUserId, Integer billBelong, AdminSalarySettlementRecord record) {
        // 从 BD 结算记录查询数据
        BdSalarySettlementRecord bdRecord = bdSalarySettlementRecordService.getByUserIdAndBillBelong(
                adminUserId, billBelong);

        if (bdRecord == null) {
            record.setBdTeamSalaryAmount(BigDecimal.ZERO);
            record.setBdTeamSalarySalary(BigDecimal.ZERO);
            record.setBdTeamRechargeAmount(BigDecimal.ZERO);
            record.setBdTeamRechargeSalary(BigDecimal.ZERO);
            record.setBdPolicyFinalSalary(BigDecimal.ZERO);
            return;
        }

        // 计算 BD_TEAM_SALARY 政策
        BigDecimal teamSalaryAmount = bdRecord.getTeamSalaryAmount() != null ?
                bdRecord.getTeamSalaryAmount() : BigDecimal.ZERO;
        record.setBdTeamSalaryAmount(teamSalaryAmount.setScale(2, RoundingMode.DOWN));

        BigDecimal teamSalarySalary = calculateBdTeamSalaryPolicy(teamSalaryAmount, record);

        // 计算 BD_TEAM_RECHARGE 政策
        BigDecimal teamRechargeAmount = bdRecord.getTeamRechargeAmount() != null ?
                bdRecord.getTeamRechargeAmount() : BigDecimal.ZERO;
        record.setBdTeamRechargeAmount(teamRechargeAmount.setScale(2, RoundingMode.DOWN));

        BigDecimal teamRechargeSalary = calculateBdTeamRechargePolicy(teamRechargeAmount, record);

        // 取最高值
        if (teamSalarySalary.compareTo(teamRechargeSalary) >= 0) {
            record.setBdPolicyFinalSalary(teamSalarySalary);
            record.setBdPolicyHitType(AdminPolicyType.BD_TEAM_SALARY.getCode());
        } else {
            record.setBdPolicyFinalSalary(teamRechargeSalary);
            record.setBdPolicyHitType(AdminPolicyType.BD_TEAM_RECHARGE.getCode());
        }
    }

    /**
     * 计算 BD_TEAM_SALARY 政策.
     */
    private BigDecimal calculateBdTeamSalaryPolicy(BigDecimal teamSalaryAmount, AdminSalarySettlementRecord record) {
        List<AdminSalaryPolicy> policies = adminSalaryPolicyService.listEnabledByType(
                AdminPolicyType.BD_TEAM_SALARY.getCode());

        if (CollectionUtils.isEmpty(policies)) {
            record.setBdTeamSalarySalary(BigDecimal.ZERO);
            return BigDecimal.ZERO;
        }

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

        for (AdminSalaryPolicy policy : policies) {
            if (teamSalaryAmount.compareTo(policy.getRequiredTeamAmount()) >= 0) {
                // 工资 = 团队工资 × 提成比例
                BigDecimal salary = teamSalaryAmount.multiply(policy.getCommissionRate())
                        .divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
                record.setBdTeamSalarySalary(salary);
                record.setBdTeamSalaryHitLevel(policy.getLevel());
                record.setBdTeamSalaryCommissionRate(policy.getCommissionRate());
                return salary;
            }
        }

        record.setBdTeamSalarySalary(BigDecimal.ZERO);
        return BigDecimal.ZERO;
    }

    /**
     * 计算 BD_TEAM_RECHARGE 政策.
     */
    private BigDecimal calculateBdTeamRechargePolicy(BigDecimal teamRechargeAmount, AdminSalarySettlementRecord record) {
        List<AdminSalaryPolicy> policies = adminSalaryPolicyService.listEnabledByType(
                AdminPolicyType.BD_TEAM_RECHARGE.getCode());

        if (CollectionUtils.isEmpty(policies)) {
            record.setBdTeamRechargeSalary(BigDecimal.ZERO);
            return BigDecimal.ZERO;
        }

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

        for (AdminSalaryPolicy policy : policies) {
            if (teamRechargeAmount.compareTo(policy.getRequiredTeamAmount()) >= 0) {
                // 工资 = 团队充值 × 提成比例
                BigDecimal salary = teamRechargeAmount.multiply(policy.getCommissionRate())
                        .divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
                record.setBdTeamRechargeSalary(salary);
                record.setBdTeamRechargeHitLevel(policy.getLevel());
                record.setBdTeamRechargeCommissionRate(policy.getCommissionRate());
                return salary;
            }
        }

        record.setBdTeamRechargeSalary(BigDecimal.ZERO);
        return BigDecimal.ZERO;
    }

    /**
     * 发放工资到工资账户.
     */
    private void issueSalary(Long adminUserId, AdminSalarySettlementRecord 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(adminUserId);
        innerCmd.setSysOrigin(record.getSysOrigin());
        innerCmd.setSalaryType(SalaryType.ADMIN_SALARY.getCode());
        innerCmd.setEventDesc(SalaryEvent.SALARY_ADMIN.getCode());
        innerCmd.setAmount(record.getTotalSalary());
        innerCmd.setTrackId(bizNo);
        innerCmd.setBdId(adminUserId);
        userSalaryAccountClient.issueSalary(innerCmd);

        log.info("管理员 {} 工资发放成功，金额：{} USD", adminUserId, record.getTotalSalary());
    }

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

    /**
     * 转换为 CO 对象.
     */
    private AdminSalarySettlementCO convertToCO(AdminSalarySettlementRecord record) {
        AdminSalarySettlementCO co = new AdminSalarySettlementCO();
        co.setAdminUserId(record.getAdminUserId());
        co.setBillBelong(record.getBillBelong());
        co.setBillTitle(record.getBillTitle());
        co.setRechargeAgentAmount(record.getRechargeAgentAmount());
        co.setRechargeAgentSalary(record.getRechargeAgentSalary());
        co.setBdLeaderTeamSalary(record.getBdLeaderTeamSalary());
        co.setBdLeaderSalary(record.getBdLeaderSalary());
        co.setBdTeamSalaryAmount(record.getBdTeamSalaryAmount());
        co.setBdTeamSalarySalary(record.getBdTeamSalarySalary());
        co.setBdTeamRechargeAmount(record.getBdTeamRechargeAmount());
        co.setBdTeamRechargeSalary(record.getBdTeamRechargeSalary());
        co.setBdPolicyFinalSalary(record.getBdPolicyFinalSalary());
        co.setBdPolicyHitType(record.getBdPolicyHitType());
        co.setTotalSalary(record.getTotalSalary());
        co.setStatus(record.getStatus() != null ? record.getStatus().name() : null);
        co.setFailureReason(record.getFailureReason());
        return co;
    }
}
