package com.yd.csf.service.service.impl;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.enums.FortuneAccountStatusEnum;
import com.yd.csf.service.enums.FortuneStatusEnum;
import com.yd.csf.service.model.ExpectedFortune;
import com.yd.csf.service.model.Fortune;
import com.yd.csf.service.model.FortuneAccount;
import com.yd.csf.service.model.FortuneAccountEditRecord;
import com.yd.csf.service.service.FortuneAccountEditRecordService;
import com.yd.csf.service.service.FortuneAccountService;
import com.yd.csf.service.dao.FortuneAccountMapper;
import com.yd.csf.service.service.FortuneService;
import com.yd.csf.service.service.IExpectedFortuneService;
import com.yd.csf.service.vo.FortuneAccountVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author Zhang Jianan
* @description 针对表【fortune_account(出账记录表)】的数据库操作Service实现
* @createDate 2025-09-23 15:45:32
*/
@Service
public class FortuneAccountServiceImpl extends ServiceImpl<FortuneAccountMapper, FortuneAccount>
    implements FortuneAccountService{

    @Resource
    private FortuneService fortuneService;

    @Resource
    private FortuneAccountEditRecordService fortuneAccountEditRecordService;

    @Resource
    private IExpectedFortuneService expectedFortuneService;

    private final Gson GSON = new Gson();

    @Override
    public QueryWrapper<FortuneAccount> getQueryWrapper(FortuneAccountQueryRequest fortuneAccountQueryRequest) {
        QueryWrapper<FortuneAccount> queryWrapper = new QueryWrapper<>();
        if (fortuneAccountQueryRequest == null) {
            return queryWrapper;
        }
        List<String> statusList = fortuneAccountQueryRequest.getStatusList();
        List<String> brokerBizIdList = fortuneAccountQueryRequest.getBrokerBizIdList();
        List<String> teamBizIdList = fortuneAccountQueryRequest.getTeamBizIdList();
        queryWrapper.in(CollectionUtils.isNotEmpty(brokerBizIdList), "broker_biz_id", brokerBizIdList);
        queryWrapper.in(CollectionUtils.isNotEmpty(teamBizIdList), "team_biz_id", teamBizIdList);

        queryWrapper.eq(StringUtils.isNotBlank(fortuneAccountQueryRequest.getBroker()), "broker", fortuneAccountQueryRequest.getBroker());
        queryWrapper.eq(StringUtils.isNotBlank(fortuneAccountQueryRequest.getTeam()), "team", fortuneAccountQueryRequest.getTeam());
        queryWrapper.in(CollectionUtils.isNotEmpty(statusList), "status", statusList);
        queryWrapper.ge(fortuneAccountQueryRequest.getAccountDateStart() != null, "fortune_account_date", fortuneAccountQueryRequest.getAccountDateStart());
        queryWrapper.le(fortuneAccountQueryRequest.getAccountDateEnd() != null, "fortune_account_date", fortuneAccountQueryRequest.getAccountDateEnd());

        // 默认排序
        queryWrapper.orderByDesc("fortune_account_date");
        return queryWrapper;
    }

    @Override
    public Page<FortuneAccountVO> getFortuneAccountVOPage(Page<FortuneAccount> fortunePage) {
        List<FortuneAccount> fortuneAccountList = fortunePage.getRecords();
        Page<FortuneAccountVO> fortuneAccountVOPage = new Page<>(fortunePage.getCurrent(), fortunePage.getSize(), fortunePage.getTotal());

        if (CollectionUtils.isEmpty(fortuneAccountList)) {
            return fortuneAccountVOPage;
        }

        List<FortuneAccountVO> fortuneAccountVOList = new ArrayList<>();
        for (FortuneAccount fortuneAccount : fortuneAccountList) {
            FortuneAccountVO fortuneAccountVO = FortuneAccountVO.objToVo(fortuneAccount);
            fortuneAccountVO.setFortuneList(GSON.fromJson(fortuneAccount.getContent(), new TypeToken<List<Map<String, Object>>>(){}.getType()));
            fortuneAccountVOList.add(fortuneAccountVO);
        }

        fortuneAccountVOPage.setRecords(fortuneAccountVOList);
        return fortuneAccountVOPage;
    }

    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public void saveFortuneAccount(List<FortuneAccountExportDTO> accountExportDTOList) {
        if (CollectionUtils.isEmpty(accountExportDTOList)) {
            return;
        }
        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        Long loginUserId = currentLoginUser.getId();

        List<FortuneAccount> fortuneAccountList = new ArrayList<>();
        Date currentDate = new Date();
        for (FortuneAccountExportDTO accountExportDTO : accountExportDTOList) {
            FortuneAccount fortuneAccount = new FortuneAccount();
            fortuneAccount.setFortuneAccountBizId(RandomStringGenerator.generateBizId16("fortune_account"));
            fortuneAccount.setBroker(accountExportDTO.getBroker());
            fortuneAccount.setTeam(accountExportDTO.getTeam());
            fortuneAccount.setCurrency(accountExportDTO.getCurrency());
            fortuneAccount.setAmount(accountExportDTO.getAmount());
            fortuneAccount.setFortuneAccountDate(currentDate);
            // 出账状态默认待出账
            fortuneAccount.setStatus(FortuneAccountStatusEnum.CANSEND.getItemValue());

            // 转换为List<Map<String, Object>>
            Map<String, BigDecimal> fortuneAmounts = accountExportDTO.getFortuneAmounts();
            List<Map<String, Object>> fortuneList = new ArrayList<>();
            for (Map.Entry<String, BigDecimal> entry : fortuneAmounts.entrySet()) {
                Map<String, Object> fortune = new HashMap<>();
                fortune.put("fortuneName", entry.getKey());
                fortune.put("amount", entry.getValue());
                fortuneList.add(fortune);
            }
            fortuneAccount.setContent(GSON.toJson(fortuneList));
            fortuneAccount.setFortuneList(accountExportDTO.getFortuneList());
            fortuneAccount.setCreatorId(loginUserId.toString());
            fortuneAccount.setUpdaterId(loginUserId.toString());
            fortuneAccount.setCreateTime(currentDate);
            fortuneAccount.setUpdateTime(currentDate);

            fortuneAccountList.add(fortuneAccount);
        }
        // 保存出账记录
        this.saveBatch(fortuneAccountList);

        // 处理关联发佣记录
        List<Fortune> updateFortuneList = new ArrayList<>();
        for (FortuneAccount fortuneAccount : fortuneAccountList) {
            String fortuneAccountBizId = fortuneAccount.getFortuneAccountBizId();
            List<Fortune> fortuneList = fortuneAccount.getFortuneList();
            if (CollectionUtils.isNotEmpty(fortuneList)) {
                for (Fortune item : fortuneList) {
                    Fortune updateFortune = new Fortune();
                    updateFortune.setId(item.getId());
                    updateFortune.setFortuneAccountBizId(fortuneAccountBizId);
                    updateFortune.setStatus(FortuneStatusEnum.CHECKED.getItemValue());
                    updateFortuneList.add(updateFortune);
                }
            }
        }

        // 更新发佣记录的出账记录id
        if (CollectionUtils.isNotEmpty(updateFortuneList)) {
            fortuneService.updateBatchById(updateFortuneList);
        }

    }

    @Override
    public FortuneAccount getByFortuneAccountBizId(String fortuneAccountBizId) {
        return this.getOne(new QueryWrapper<FortuneAccount>().eq("fortune_account_biz_id", fortuneAccountBizId));
    }

    @Override
    public Map<String, Object> addFortuneAccount(FortuneAccountAddRequest fortuneAccountAddRequest) {
        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        Long loginUserId = currentLoginUser.getId();

        FortuneAccount fortuneAccount = new FortuneAccount();
        BeanUtils.copyProperties(fortuneAccountAddRequest, fortuneAccount);

        fortuneAccount.setFortuneAccountBizId(RandomStringGenerator.generateBizId16("fortune_account"));
        fortuneAccount.setRemark(fortuneAccountAddRequest.getRemark());
        fortuneAccount.setCreatorId(loginUserId.toString());
        fortuneAccount.setUpdaterId(loginUserId.toString());
        fortuneAccount.setCreateTime(new Date());
        fortuneAccount.setUpdateTime(new Date());

        this.save(fortuneAccount);
        return Collections.singletonMap("fortuneAccountBizId", fortuneAccount.getFortuneAccountBizId());
    }

    @Override
    public Boolean updateFortuneAccount(FortuneAccountUpdateRequest fortuneAccountUpdateRequest) {
        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        Long loginUserId = currentLoginUser.getId();

        FortuneAccount fortuneAccount = this.getByFortuneAccountBizId(fortuneAccountUpdateRequest.getFortuneAccountBizId());
        if (fortuneAccount == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), ResultCode.NULL_ERROR.getMessage());
        }
        // 保存修改记录
        saveUpdateFortuneAccountRecord(fortuneAccount, fortuneAccountUpdateRequest);

        BeanUtils.copyProperties(fortuneAccountUpdateRequest, fortuneAccount, "fortuneAccountBizId");
        fortuneAccount.setUpdaterId(loginUserId.toString());
        fortuneAccount.setUpdateTime(new Date());

        this.updateById(fortuneAccount);

        return true;
    }

    private void saveUpdateFortuneAccountRecord(FortuneAccount fortuneAccount, FortuneAccountUpdateRequest fortuneAccountUpdateRequest) {
        FortuneAccountEditRecord fortuneAccountEditRecord = new FortuneAccountEditRecord();
        // 薪资记录业务id
        fortuneAccountEditRecord.setFortuneAccountBizId(fortuneAccount.getFortuneAccountBizId());
        fortuneAccountEditRecord.setIsDeleted(0);
        fortuneAccountEditRecord.setCreateTime(new Date());
        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        Long loginUserId = currentLoginUser.getId();

        fortuneAccountEditRecord.setUserBizId(loginUserId.toString());
        fortuneAccountEditRecord.setUserName(currentLoginUser.getUsername());

        // 构建修改内容
        StringBuilder editContentBuilder = new StringBuilder();
        editContentBuilder.append("修改了薪资记录:");
        editContentBuilder.append("转介人:").append(fortuneAccountUpdateRequest.getBroker()).append(";");
        editContentBuilder.append("团队:").append(fortuneAccountUpdateRequest.getTeam()).append(";");
        editContentBuilder.append("出账金额:").append(fortuneAccountUpdateRequest.getAmount()).append(";");
        editContentBuilder.append("出账币种:").append(fortuneAccountUpdateRequest.getCurrency()).append(";");
        if (StringUtils.isNotBlank(fortuneAccountUpdateRequest.getRemark())) {
            editContentBuilder.append("备注:").append(fortuneAccountUpdateRequest.getRemark()).append(";");
        }

        fortuneAccountEditRecord.setEditContent(editContentBuilder.toString());
        fortuneAccountEditRecord.setRemark(fortuneAccountUpdateRequest.getRemark());

        fortuneAccountEditRecordService.save(fortuneAccountEditRecord);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean completeFortuneAccount(CompleteFortuneAccountRequest req) {
        /* 1. 参数校验 & 查询 --------------------------------------------------*/
        List<String> accountBizIds = req.getFortuneAccountBizIdList();
        if (CollectionUtils.isEmpty(accountBizIds)) {
            throw new BusinessException("出账清单不能为空");
        }
        List<FortuneAccount> accountList = this.lambdaQuery()
                .in(FortuneAccount::getFortuneAccountBizId, accountBizIds)
                .list();

        Long loginUserId = SecurityUtil.getCurrentLoginUser().getId();

        /* 2. 更新 FortuneAccount 状态为已出账 ----------------------------------*/
        accountList.forEach(a -> {
            a.setStatus(FortuneAccountStatusEnum.SENT.getItemValue());
            a.setFortuneAccountDate(new Date());
            a.setUpdaterId(loginUserId.toString());
            a.setUpdateTime(new Date());
        });
        this.updateBatchById(accountList);

        /* 3. 取出关联的所有 fortune 并一次性更新为已出账 ------------------------*/
        List<String> accountBizIdList = accountList.stream()
                .map(FortuneAccount::getFortuneAccountBizId).collect(Collectors.toList());

        List<Fortune> fortunes = fortuneService.lambdaQuery()
                .in(Fortune::getFortuneAccountBizId, accountBizIdList)
                .eq(Fortune::getStatus, FortuneStatusEnum.CHECKED.getItemValue())
                .list();
        if (CollectionUtils.isNotEmpty(fortunes)) {
            fortunes.forEach(f -> {
                f.setStatus(FortuneStatusEnum.SENT.getItemValue());
                f.setActualPayoutDate(LocalDate.now());
                f.setUpdaterId(loginUserId.toString());
                f.setUpdateTime(new Date());
            });
            fortuneService.updateBatchById(fortunes);
        }

        /* 4. 按 expected_fortune 维度重新汇总已出账金额 --------------------------*/
        // 4.1 收集所有涉及的 expectedFortuneBizId
        Set<String> expectedIds = fortunes.stream()
                .map(Fortune::getExpectedFortuneBizId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(expectedIds)) {
            return true; // 没有对应预计出账，直接结束
        }

        // 4.2 先锁再算
        List<ExpectedFortune> expectedList = expectedFortuneService.lambdaQuery()
                .in(ExpectedFortune::getExpectedFortuneBizId, expectedIds)
                .last("FOR UPDATE")
                .list();

        // 4.3 全量汇总：把同一 expected_fortune 下所有 fortune 的 current_payment_amount 求和
        Map<String, BigDecimal> paidMap = fortuneService.lambdaQuery()
                .in(Fortune::getExpectedFortuneBizId, expectedIds)
                .eq(Fortune::getStatus, FortuneStatusEnum.SENT.getItemValue())
                .list()
                .stream()
                .collect(Collectors.groupingBy(Fortune::getExpectedFortuneBizId,
                        Collectors.mapping(Fortune::getCurrentPaymentAmount,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

        // 4.4 反写 expected_fortune
        expectedList.forEach(ef -> {
            BigDecimal totalPaid = paidMap.getOrDefault(ef.getExpectedFortuneBizId(), BigDecimal.ZERO);
            BigDecimal totalAmount = ef.getAmount();
            BigDecimal unpaid = totalAmount.subtract(totalPaid);

            String newStatus;
            if (unpaid.compareTo(BigDecimal.ZERO) == 0) {
                newStatus = FortuneStatusEnum.SENT.getItemValue();        // 全部完成
            } else if (totalPaid.compareTo(BigDecimal.ZERO) > 0) {
                newStatus = FortuneStatusEnum.PARTIAL_SENT.getItemValue(); // 部分完成
            } else {
                newStatus = ef.getStatus();                               // 无变化
            }

            expectedFortuneService.lambdaUpdate()
                    .set(ExpectedFortune::getPaidAmount, totalPaid)
                    .set(ExpectedFortune::getUnpaidAmount, unpaid)
                    .set(ExpectedFortune::getPaidRatio,
                            totalPaid.divide(totalAmount, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)))
                    .set(ExpectedFortune::getUnpaidRatio,
                            unpaid.divide(totalAmount, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)))
                    .set(ExpectedFortune::getStatus, newStatus)
                    .set(ExpectedFortune::getUpdaterId, loginUserId.toString())
                    .set(ExpectedFortune::getUpdateTime, LocalDateTime.now())
                    .eq(ExpectedFortune::getId, ef.getId())
                    .update();
        });

        return true;
    }

    @Override
    public FortuneAccountStatisticsVO getFortuneAccountStatistics(List<Long> fortuneAccountIdList) {
        if (CollectionUtils.isEmpty(fortuneAccountIdList)) {
            FortuneAccountStatisticsVO vo = new FortuneAccountStatisticsVO();
            vo.setTotalAmount(BigDecimal.ZERO);
            vo.setBrokerCount(0L);
            return vo;
        }

        // 统计总金额和总人数
        List<FortuneAccount> fortuneAccountList = this.baseMapper.selectBatchIds(fortuneAccountIdList);

        BigDecimal totalAmount = fortuneAccountList.stream()
                .map(FortuneAccount::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        int brokerCount = fortuneAccountList.stream()
                .map(FortuneAccount::getBroker)
                .collect(Collectors.toSet()).size();

        FortuneAccountStatisticsVO vo = new FortuneAccountStatisticsVO();
        vo.setTotalAmount(totalAmount);
        vo.setBrokerCount(brokerCount);
        return vo;
    }
}




