package com.yd.csf.api.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.CodeGenerator;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.service.ApiSalaryRemittanceService;
import com.yd.csf.api.service.ApiSalaryService;
import com.yd.csf.feign.dto.salary.ApiSalaryBatchAddDTO;
import com.yd.csf.feign.dto.salary.CalculateTotalAmountDTO;
import com.yd.csf.feign.dto.salaryremittance.ApiSalaryRemittanceDTO;
import com.yd.csf.feign.dto.salaryremittance.ApiSalaryRemittanceFzDTO;
import com.yd.csf.feign.request.salary.*;
import com.yd.csf.feign.response.salary.ApiSalaryDetailResponse;
import com.yd.csf.feign.response.salary.ApiSalaryPageResponse;
import com.yd.csf.feign.response.salary.ApiSalaryPushPageResponse;
import com.yd.csf.service.model.Salary;
import com.yd.csf.service.model.SalaryRemittance;
import com.yd.csf.service.service.ISalaryRemittanceService;
import com.yd.csf.service.service.ISalaryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApiSalaryServiceImpl implements ApiSalaryService {

    @Autowired
    private ISalaryService iSalaryService;

    @Autowired
    private ApiSalaryRemittanceService apiSalaryRemittanceService;

    @Autowired
    private ISalaryRemittanceService iSalaryRemittanceService;

    /**
     * 分页查询-制作薪资单列表信息
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiSalaryPageResponse>> page(ApiSalaryPageRequest request) {
        Page<ApiSalaryPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiSalaryPageResponse> iPage = iSalaryService.page(page, request);
        return Result.success(iPage);
    }

    /**
     * 分页查询-电子薪资单列表信息（推送列表信息）
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiSalaryPushPageResponse>> pushPage(ApiSalaryPushPageRequest request) {
        Page<ApiSalaryPushPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
//        IPage<ApiSalaryPushPageResponse> iPage = iSalaryService.pushPage(page, request);
        return Result.success();
    }

    /**
     * 详情-薪资单信息
     * @param salaryBizId
     * @return
     */
    @Override
    public Result<ApiSalaryDetailResponse> detail(String salaryBizId) {
        //校验薪资单信息是否存在
        Salary salary = checkIsExist(salaryBizId);
        ApiSalaryDetailResponse response = new ApiSalaryDetailResponse();
        BeanUtils.copyProperties(salary,response);
        //薪资汇款明细封装的DTO
        ApiSalaryRemittanceFzDTO fzDTO = new ApiSalaryRemittanceFzDTO();
        fzDTO.setTotalAmount(salary.getPaidAmount());
        List<ApiSalaryRemittanceDTO> salaryRemittanceDTOList = new ArrayList<>();
        List<SalaryRemittance> salaryRemittanceList = iSalaryRemittanceService.queryList(salaryBizId);
        if (CollectionUtils.isNotEmpty(salaryRemittanceList)) {
            salaryRemittanceDTOList = salaryRemittanceList.stream().map(dto -> {
                ApiSalaryRemittanceDTO remittanceDTO = new ApiSalaryRemittanceDTO();
                BeanUtils.copyProperties(dto,remittanceDTO);
                return remittanceDTO;
            }).collect(Collectors.toList());
        }
        fzDTO.setSalaryRemittanceDTOList(salaryRemittanceDTOList);
        response.setApiSalaryRemittanceFzDTO(fzDTO);
        return Result.success(response);
    }

    /**
     * 新增-薪资单信息
     * @param request
     * @return
     */
    @Override
    public Result add(ApiSalaryAddRequest request) {
        ApiSalaryRemittanceFzDTO fzDTO = request.getApiSalaryRemittanceFzDTO();
        if (fzDTO == null) {
            fzDTO = new ApiSalaryRemittanceFzDTO();
        }
        //校验金额
        checkAmount(request.getPaidAmount(),fzDTO.getTotalAmount());
        //校验同一转介人同一薪资年月只能有一条薪资单记录
        checkUniqueByBrokerMonth(request.getBrokerBizId(),request.getMonth(),"",false);
        Salary salary = new Salary();
        BeanUtils.copyProperties(request,salary);
        //发放编号
        salary.setSalaryNo(CodeGenerator.generate10Code("SN"));
        //薪资单表唯一业务ID
        salary.setSalaryBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_SALARY.getCode()));
        iSalaryService.saveOrUpdate(salary);

        //保存薪资汇款明细
        apiSalaryRemittanceService.batchSave(salary.getSalaryBizId(),fzDTO);
        return Result.success();
    }

    /**
     * 修改-薪资单信息
     * @param request
     * @return
     */
    @Override
    public Result edit(ApiSalaryEditRequest request) {
        ApiSalaryRemittanceFzDTO fzDTO = request.getApiSalaryRemittanceFzDTO();
        if (fzDTO == null) {
            fzDTO = new ApiSalaryRemittanceFzDTO();
        }
        //校验金额
        checkAmount(request.getPaidAmount(),fzDTO.getTotalAmount());
        //校验薪资单信息是否存在
        Salary salary = checkIsExist(request.getSalaryBizId());
        //校验同一转介人同一薪资年月只能有一条薪资单记录
        checkUniqueByBrokerMonth(request.getBrokerBizId(),request.getMonth(),
                request.getSalaryBizId(),true);
        BeanUtils.copyProperties(request,salary);
        iSalaryService.saveOrUpdate(salary);

        //保存薪资汇款明细
        apiSalaryRemittanceService.batchSave(salary.getSalaryBizId(),fzDTO);
        return Result.success();
    }

    /**
     * 批量新增-薪资单信息
     * @param request
     * @return
     */
    @Override
    public Result batchAdd(ApiSalaryBatchAddRequest request) {
        List<ApiSalaryBatchAddDTO> apiSalaryBatchAddDTOList = request.getApiSalaryBatchAddDTOList();
        if (CollectionUtils.isEmpty(apiSalaryBatchAddDTOList)) {
            throw new BusinessException("批量新增的数据列表不能为空");
        }
        //批量校验同一转介人同一年月只能有一条薪资单记录 TODO
        //批量校验薪资单信息金额字段信息 TODO
        Map<Salary,List<SalaryRemittance>> map = new HashMap<>();
        apiSalaryBatchAddDTOList.forEach(dto -> {
            Salary salary = new Salary();
            BeanUtils.copyProperties(dto,salary);
            salary.setSalaryBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_SALARY.getCode()));
            List<SalaryRemittance> salaryRemittanceList = new ArrayList<>();
            SalaryRemittance remittance1 = new SalaryRemittance();
            remittance1.setSalaryBizId(salary.getSalaryBizId());
            remittance1.setSalaryRemittanceBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_SALARY_REMITTANCE.getCode()));
            remittance1.setBank(dto.getBank1());
            remittance1.setAccountEndNo(dto.getAccountEndNo1());
            remittance1.setCurrency(dto.getCurrency1());
            remittance1.setAmount(dto.getAmount1());
            remittance1.setExchangeRate(dto.getExchangeRate1());
            remittance1.setRemark(dto.getRemark1());
            salaryRemittanceList.add(remittance1);
            SalaryRemittance remittance2 = new SalaryRemittance();
            remittance2.setSalaryBizId(salary.getSalaryBizId());
            remittance2.setSalaryRemittanceBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_SALARY_REMITTANCE.getCode()));
            remittance2.setBank(dto.getBank2());
            remittance2.setAccountEndNo(dto.getAccountEndNo2());
            remittance2.setCurrency(dto.getCurrency2());
            remittance2.setAmount(dto.getAmount2());
            remittance2.setExchangeRate(dto.getExchangeRate2());
            remittance2.setRemark(dto.getRemark2());
            salaryRemittanceList.add(remittance2);
            map.put(salary,salaryRemittanceList);
        });
        // 提取所有的 Salary 对象
        List<Salary> salaryList = new ArrayList<>(map.keySet());
        // 提取所有的 SalaryRemittance 对象（将 Map 中所有 List 打平）
        List<SalaryRemittance> salaryRemittanceList = map.values()
                .stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());
        //批量保存salaryList
        iSalaryService.saveOrUpdateBatch(salaryList);
        //批量保存salaryRemittanceList
        iSalaryRemittanceService.saveOrUpdateBatch(salaryRemittanceList);
        return Result.success();
    }

    /**
     * 删除-薪资单汇款明细信息
     * @param salaryRemittanceBizId
     * @return
     */
    @Override
    public Result delSalaryRemittance(String salaryRemittanceBizId) {
        SalaryRemittance salaryRemittance = iSalaryRemittanceService.queryOne(salaryRemittanceBizId);
        if (salaryRemittance == null) {
            throw new BusinessException("薪资单汇款明细信息不存在");
        }
        iSalaryRemittanceService.removeById(salaryRemittance.getId());
        return Result.success();
    }

    /**
     * 计算-实发金额
     * @param request
     * @return
     */
    @Override
    public Result<BigDecimal> calculatePaidAmount(ApiSalaryCalculatePaidAmountRequest request) {
        //应发总金额
        BigDecimal grossAmount = ObjectUtils.defaultIfNull(request.getGrossAmount(), BigDecimal.ZERO);
        //MPF事项总金额
        BigDecimal mpfAmount = ObjectUtils.defaultIfNull(request.getMpfAmount(), BigDecimal.ZERO);
        //其他调整总金额
        BigDecimal otherAmount = ObjectUtils.defaultIfNull(request.getOtherAmount(), BigDecimal.ZERO);
        //实发金额 = 应发金额-MPF事项+其他调整
        BigDecimal paidAmount = grossAmount.subtract(mpfAmount).add(otherAmount);
        return Result.success(paidAmount);
    }

    /**
     * 计算-薪资汇款明细合计发放金额（单位：HKD）
     * @param request
     * @return
     */
    @Override
    public Result<BigDecimal> calculateTotalAmount(ApiSalaryCalculateTotalAmountRequest request) {
        List<CalculateTotalAmountDTO> calculateTotalAmountDTOList = request.getCalculateTotalAmountDTOList();
        if (CollectionUtils.isEmpty(calculateTotalAmountDTOList)) {
            throw new BusinessException("计算入参的值不能为空");
        }
        BigDecimal totalAmount = BigDecimal.ZERO;
        calculateTotalAmountDTOList.forEach(dto -> {
            //发放金额
            BigDecimal amount = ObjectUtils.defaultIfNull(dto.getAmount(), BigDecimal.ZERO);
            //汇率
            BigDecimal exchangeRate = ObjectUtils.defaultIfNull(dto.getExchangeRate(), BigDecimal.ZERO);
            //港币金额 = 发放金额 * 汇率
            BigDecimal hkdAmount = amount.multiply(exchangeRate);
            totalAmount.add(hkdAmount);
        });
        return Result.success(totalAmount);
    }

    /**
     * 批量校验同一转介人同一年月只能有一条薪资单记录
     * @param apiSalaryBatchAddDTOList
     */
    public void batchCheckUniqueByBrokerMonth(List<ApiSalaryBatchAddDTO> apiSalaryBatchAddDTOList) {

    }

    /**
     * 校验同一转介人同一年月只能有一条薪资单记录
     * @param brokerBizId 转介人业务id
     * @param month 薪资月份（同出账月，如：202605）
     * @param salaryBizId 薪资单信息唯一业务ID
     * @param isExcludeMy 是否排除自己
     */
    public void checkUniqueByBrokerMonth(String brokerBizId,String month,
                                         String salaryBizId,Boolean isExcludeMy) {
        Salary salary = iSalaryService.queryOne(brokerBizId,month,salaryBizId,isExcludeMy);
        if (salary != null) {
            throw new BusinessException("同一转介人同一薪资年月只能有一条薪资单记录");
        }
    }

    /**
     * 校验薪资单信息金额字段信息
     * @param paidAmount
     * @param totalAmount
     * @return
     */
    public void checkAmount(BigDecimal paidAmount,BigDecimal totalAmount) {
        paidAmount = ObjectUtils.defaultIfNull(paidAmount, BigDecimal.ZERO);
        totalAmount = ObjectUtils.defaultIfNull(totalAmount, BigDecimal.ZERO);
        if (paidAmount.compareTo(totalAmount) != 0) {
            //汇款明细合计总金额和实发总金额必须相等
            throw new BusinessException("汇款明细合计总金额和实发总金额必须相等");
        }
    }

    /**
     * 校验薪资单信息是否存在
     * @param salaryBizId
     */
    public Salary checkIsExist(String salaryBizId) {
        Salary salary = iSalaryService.queryOne(salaryBizId);
        if (salary == null) {
            throw new BusinessException("薪资单信息不存在");
        }
        return salary;
    }

}
