package com.yd.csf.service.service.impl;
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.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;
        }
        queryWrapper.eq(StringUtils.isNotBlank(fortuneAccountQueryRequest.getBroker()), "broker", fortuneAccountQueryRequest.getBroker());
        queryWrapper.eq(StringUtils.isNotBlank(fortuneAccountQueryRequest.getTeam()), "team", fortuneAccountQueryRequest.getTeam());
        queryWrapper.eq(StringUtils.isNotBlank(fortuneAccountQueryRequest.getStatus()), "status", fortuneAccountQueryRequest.getStatus());
        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);
                    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();
        fortuneAccount.setFortuneAccountBizId(RandomStringGenerator.generateBizId16("fortune_account"));
        fortuneAccount.setBroker(fortuneAccountAddRequest.getBroker());
        fortuneAccount.setTeam(fortuneAccountAddRequest.getTeam());
        fortuneAccount.setCurrency(fortuneAccountAddRequest.getCurrency());
        fortuneAccount.setAmount(fortuneAccountAddRequest.getAmount());
        fortuneAccount.setFortuneAccountDate(fortuneAccountAddRequest.getFortuneAccountDate());
        fortuneAccount.setStatus(fortuneAccountAddRequest.getStatus());
        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);

        fortuneAccount.setBroker(fortuneAccountUpdateRequest.getBroker());
        fortuneAccount.setTeam(fortuneAccountUpdateRequest.getTeam());
        fortuneAccount.setCurrency(fortuneAccountUpdateRequest.getCurrency());
        fortuneAccount.setAmount(fortuneAccountUpdateRequest.getAmount());
        fortuneAccount.setFortuneAccountDate(fortuneAccountUpdateRequest.getFortuneAccountDate());
        fortuneAccount.setRemark(fortuneAccountUpdateRequest.getRemark());
        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 completeFortuneAccountRequest) {

        List<String> fortuneAccountBizIdList = completeFortuneAccountRequest.getFortuneAccountBizIdList();
        List<FortuneAccount> fortuneAccountList = this.list(new QueryWrapper<FortuneAccount>().in("fortune_account_biz_id", fortuneAccountBizIdList));
        if (CollectionUtils.isEmpty(fortuneAccountList)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), ResultCode.NULL_ERROR.getMessage());
        }

        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        Long loginUserId = currentLoginUser.getId();

        // 更新 FortuneAccount 状态为已出账
        for (FortuneAccount fortuneAccount : fortuneAccountList) {
            fortuneAccount.setStatus(FortuneAccountStatusEnum.SENT.getItemValue());
            fortuneAccount.setUpdaterId(loginUserId.toString());
            fortuneAccount.setUpdateTime(new Date());
        }
        this.updateBatchById(fortuneAccountList);

        // 更新 Fortune 状态为已出账
        List<String> accountBizIdList = fortuneAccountList.stream().map(FortuneAccount::getFortuneAccountBizId).collect(Collectors.toList());
        List<Fortune> updateFortuneList = fortuneService.list(new QueryWrapper<Fortune>().in("fortune_account_biz_id", accountBizIdList));
        if (CollectionUtils.isNotEmpty(updateFortuneList)) {
            for (Fortune item : updateFortuneList) {
                item.setStatus(FortuneStatusEnum.SENT.getItemValue());
                item.setUpdaterId(loginUserId.toString());
                item.setUpdateTime(new Date());
            }
            fortuneService.updateBatchById(updateFortuneList);
        }

        // 更新预计出账记录
        List<String> expectedFortuneBizIdList = updateFortuneList.stream().map(Fortune::getExpectedFortuneBizId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(expectedFortuneBizIdList)) {
            List<ExpectedFortune> expectedFortuneList = expectedFortuneService.list(new QueryWrapper<ExpectedFortune>().in("expected_fortune_biz_id", expectedFortuneBizIdList));
            // 预计出账映射
            Map<String, ExpectedFortune> expectedFortuneMap = expectedFortuneList.stream()
                    .collect(Collectors.toMap(ExpectedFortune::getExpectedFortuneBizId, Function.identity()));
            // 遍历本次出账记录，更新预计出账记录
            for (Fortune item : updateFortuneList) {
                ExpectedFortune expectedFortune = expectedFortuneMap.get(item.getExpectedFortuneBizId());
                if (Objects.nonNull(expectedFortune)) {
                    BigDecimal amount = item.getAmount();// 本次出账金额
                    BigDecimal paidAmount = expectedFortune.getPaidAmount();// 已出账金额
                    if (expectedFortune.getAmount().compareTo(paidAmount.add(amount)) == 0) {
                        // 已出账金额等于预计出账金额，更新状态为完成出账
                        expectedFortune.setPaidAmount(paidAmount.add(amount));
                        expectedFortune.setUnpaidAmount(BigDecimal.ZERO);
                        expectedFortune.setStatus(FortuneStatusEnum.SENT.getItemValue());
                    } else {
                        // 已出账金额小于预计出账金额，更新已出账金额
                        expectedFortune.setPaidAmount(paidAmount.add(amount));
                        expectedFortune.setUnpaidAmount(expectedFortune.getAmount().subtract(paidAmount.add(amount)));
                        expectedFortune.setUpdaterId(loginUserId.toString());
                        expectedFortune.setUpdateTime(LocalDateTime.now());
                    }
                }
            }
            // 更新预计出账记录
            expectedFortuneService.updateBatchById(expectedFortuneList);
        }

        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;
    }
}




