package com.kym.service.admin.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.github.pagehelper.PageHelper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.admin.*;
import com.kym.entity.admin.queryParams.StatementsQueryParam;
import com.kym.entity.admin.vo.StatementsVo;
import com.kym.entity.common.PageBean;
import com.kym.mapper.admin.StatementsMapper;
import com.kym.service.admin.AdminUserRoleService;
import com.kym.service.admin.InvestorInfoService;
import com.kym.service.admin.StatementsService;
import com.kym.service.admin.StationStatMonthService;
import com.kym.service.cache.KymCache;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 客户对账单 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2023-12-27
 */
@Service
@DS("db-admin")
public class StatementsServiceImpl extends MPJBaseServiceImpl<StatementsMapper, Statements> implements StatementsService {

    private final InvestorInfoService investorInfoService;

    private final StationStatMonthService stationStatMonthService;

    private final AdminUserRoleService adminUserRoleService;

    public StatementsServiceImpl(InvestorInfoService investorInfoService, StationStatMonthService stationStatMonthService, AdminUserRoleService adminUserRoleService) {
        this.investorInfoService = investorInfoService;
        this.stationStatMonthService = stationStatMonthService;
        this.adminUserRoleService = adminUserRoleService;
    }

    @Override
    @Transactional
    public void createStatements(String statMonthId) {
        // 站点统计信息
        var statMonthInfo = stationStatMonthService.lambdaQuery()
                .eq(StationStatMonth::getId, statMonthId)
                .one();

        // 校验站点月统计信息已填写实际抄表电量和实际抄表电费金额
        if (statMonthInfo.getActualPower() == null || statMonthInfo.getActualElecMoney() == null) {
            throw new BusinessException("请先完善月统计实际抄表电量和实际抄表电费金额");
        }

        // 站点关联客户和物业信息
        var investorInfoList = investorInfoService.lambdaQuery()
                .eq(InvestorInfo::getStationId, statMonthInfo.getStationId())
                .eq(InvestorInfo::getStatus, InvestorInfo.STATUS_有效)
                .list();

        if (CommUtil.isEmptyOrNull(investorInfoList)) {
            throw new BusinessException("请先完善站点相关投资者/物业信息");
        }

        // 创建客户对账单
        var res = investorInfoList.stream().map(investorInfo -> {
            // 实际参与分成的服务费=总服务费-优惠金额-电损电费
            var actualServiceMoney = statMonthInfo.getServiceMoney() - statMonthInfo.getDiscountAmount();
            // 总电损电费
            var elecLossMoney = statMonthInfo.getActualElecMoney() - statMonthInfo.getElecMoney();
            var elecLossAmount = (int) (elecLossMoney * investorInfo.getElecLossProportion());
            // 分成金额 = 实际参与分成的服务费 * 分成比例 - 电损金额 * 电损承担比例
            var splittingAmount = (int) (actualServiceMoney * investorInfo.getSplittingProportion()) - elecLossAmount;
            return new Statements()
                    .setAdminUserId(investorInfo.getAdminUserId())
                    .setAdminUserName(investorInfo.getAdminUserName())
                    .setStationId(investorInfo.getStationId())
                    .setStationName(KymCache.INSTANCE.getStationNameById(investorInfo.getStationId()))
                    .setStatMonth(statMonthInfo.getStatMonth())
                    .setTotalPower(statMonthInfo.getTotalPower())
                    .setActualPower(statMonthInfo.getActualPower()) // 实际抄表电量
                    .setElecLossPower(statMonthInfo.getActualPower() - statMonthInfo.getTotalPower()) // 电损电量
                    .setTotalMoney(statMonthInfo.getTotalMoney())
                    .setElecMoney(statMonthInfo.getElecMoney())
                    .setActualElecMoney(statMonthInfo.getActualElecMoney())// 实际抄表电费
                    .setElecLossMoney(elecLossMoney) // 电损电费（分）
                    .setServiceMoney(statMonthInfo.getServiceMoney())
                    .setDiscountAmount(statMonthInfo.getDiscountAmount())
                    .setServiceMoneyDiscount(statMonthInfo.getServiceMoneyDiscount())
                    .setActualServiceMoney(actualServiceMoney) // 实际参与分成的服务费（分）
                    .setSplittingProportion(investorInfo.getSplittingProportion()) // 分成比例 0.45表示45%
                    .setSplittingAmount(splittingAmount)  // 分成金额（分）
                    .setElecLossProportion(investorInfo.getElecLossProportion()) // 电损承担比例
                    .setElecLossAmount((int) (elecLossMoney * investorInfo.getElecLossProportion()))    // 电损承担金额
                    .setVatRate(investorInfo.getVatRate()) // 增值税率 0.06表示6%
                    .setVatAmount((int) (splittingAmount / (1 + investorInfo.getVatRate()) * investorInfo.getVatRate() * 1.12)) // 增值税额（分）
                    .setActualSplittingAmount(splittingAmount - (int) (splittingAmount / (1 + investorInfo.getVatRate()) * investorInfo.getVatRate() * 1.12)); // 实际分成金额（分）
        }).toList();
        // 删除之前生成的对账单（投资者/物业 - 站点 - 月份）
        var oldData = lambdaQuery()
                .eq(Statements::getStatMonth, statMonthInfo.getStatMonth())
                .eq(Statements::getStationId, statMonthInfo.getStationId())
                .in(Statements::getAdminUserId, investorInfoList.stream().map(InvestorInfo::getAdminUserId).toList())
                .list().stream().map(Statements::getId).toList();
        removeBatchByIds(oldData);
        saveBatch(res);
    }

    @Override
    public PageBean<Statements> listStatements(StatementsQueryParam params) {
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var res = lambdaQuery()
                .eq(!CommUtil.isEmptyOrNull(params.getStationId()), Statements::getStationId, params.getStationId())
                .eq(!CommUtil.isEmptyOrNull(params.getStatMonth()), Statements::getStatMonth, params.getStatMonth())
                .like(!CommUtil.isEmptyOrNull(params.getAdminUserName()), Statements::getAdminUserName, params.getAdminUserName())
                .orderByDesc(Statements::getCreateTime)
                .list();
        return new PageBean<>(res);
    }

    @Override
    public StatementsVo preview(String statId) {
        var statements = getById(statId);
        var investorInfo = investorInfoService.lambdaQuery()
                .eq(InvestorInfo::getAdminUserId, statements.getAdminUserId())
                .eq(InvestorInfo::getStationId, statements.getStationId())
                .one();
        // 查询角色
        MPJLambdaWrapper<AdminUserRole> wrapper = JoinWrappers.lambda(AdminUserRole.class)
                .select(Role::getRoleName, Role::getRoleDesc)
                .leftJoin(Role.class, Role::getId, AdminUserRole::getRoleId)
                .eq(AdminUserRole::getAdminUserId, statements.getAdminUserId());
        var res = adminUserRoleService.selectJoinMap(wrapper);

        if (CommUtil.isEmptyOrNull(res)) {
            throw new BusinessException("请先完善站点相关投资者/物业客户账号信息关联之后重新生成账单");
        }

        var statementsVo = new StatementsVo();
        statementsVo.setRoleName(res.get("role_name").toString());
        statementsVo.setRoleDesc(res.get("role_desc").toString());
        BeanUtils.copyProperties(statements, statementsVo);
        BeanUtils.copyProperties(investorInfo, statementsVo);
        return statementsVo;
    }
}
