package cn.iocoder.yudao.module.system.service.customersettlement;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.api.customersettlement.dto.SettlementItemDTO;
import cn.iocoder.yudao.module.system.controller.admin.customersettlement.vo.CustomerSettlementPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.customersettlement.vo.CustomerSettlementSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.customersettlement.vo.StatisticsVO;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.upload.UploadUserFile;
import cn.iocoder.yudao.module.system.dal.dataobject.customersettlement.CustomerSettlementDO;
import cn.iocoder.yudao.module.system.dal.dataobject.customersettlement.SettlementItemDO;
import cn.iocoder.yudao.module.system.dal.mysql.customersettlement.CustomerSettlementMapper;
import cn.iocoder.yudao.module.system.dal.mysql.customersettlement.SettlementItemMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 客户结算信息 Service 实现类
 *
 * @author 陈宾顺
 */
@Service
@Validated
public class CustomerSettlementServiceImpl implements CustomerSettlementService {

    @Resource
    private CustomerSettlementMapper customerSettlementMapper;

    @Resource
    private SettlementItemMapper settlementItemMapper;

    @Resource
    private FileApi fileApi;

    @Override
    public Long createCustomerSettlement(CustomerSettlementSaveReqVO createReqVO) {
        // 检验该厂区 结算记录是否存在
        Long count = customerSettlementMapper.selectCount(new LambdaQueryWrapperX<CustomerSettlementDO>()
                .eq(CustomerSettlementDO::getCustomerId, createReqVO.getCustomerId())
                .eq(CustomerSettlementDO::getSettlementMonth, createReqVO.getSettlementMonth()));
        if (count > 0L) {
            throw exception(CUSTOMER_SETTLEMENT_EXISTS);
        }

        // 插入
        CustomerSettlementDO customerSettlement = BeanUtils.toBean(createReqVO, CustomerSettlementDO.class);
        customerSettlementMapper.insert(customerSettlement);

        // 插入结算明细
        List<SettlementItemDO> itemDO = BeanUtils.toBean(createReqVO.getSettlementItems(), SettlementItemDO.class);
        if (CollUtil.isNotEmpty(itemDO)) {
            itemDO.forEach(item -> item.setSettlementId(customerSettlement.getId()));
            settlementItemMapper.insertBatch(itemDO);
        }

        if (CollUtil.isNotEmpty(customerSettlement.getFileItems())) {
            // 更新交易凭证附件 业务编号
            UpdateBusinessFile(customerSettlement);
        }

        // 返回
        return customerSettlement.getId();
    }

    private void UpdateBusinessFile(CustomerSettlementDO updateReqVO) {

        List<String> urls = updateReqVO.getFileItems().stream().map(UploadUserFile::getUrl).collect(Collectors.toList());
        fileApi.updateBusinessFile(urls, updateReqVO.getId().toString());
    }

    @Override
    public void updateCustomerSettlement(CustomerSettlementSaveReqVO updateReqVO) {
        // 校验存在
        CustomerSettlementDO settlementDO = validateCustomerSettlementExists(updateReqVO.getId());

        // 检验是否已过可以编辑预结算金额时间
        LocalDate now = LocalDate.now();
        LocalDate createDate = settlementDO.getCreateTime().toLocalDate();
        if (ChronoUnit.MONTHS.between(now, createDate) > 0) {
            throw exception(CUSTOMER_SETTLEMENT_NOT_EDIT);
        }

        // 更新
        CustomerSettlementDO updateObj = BeanUtils.toBean(updateReqVO, CustomerSettlementDO.class);

        // 同步更新结算明细
        if (CollUtil.isNotEmpty(updateReqVO.getSettlementItems())) {
            // 获取需创建的 结算明细
            List<SettlementItemDO> createDO = BeanUtils.toBean(updateReqVO.getSettlementItems(), SettlementItemDO.class).stream()
                    .filter(item -> item.getId() == null)
                    .map(item -> item.setSettlementId(updateReqVO.getId()))
                    .collect(Collectors.toList());
            // 获取需更新的 结算明细
            List<SettlementItemDO> updateDO = BeanUtils.toBean(updateReqVO.getSettlementItems(), SettlementItemDO.class).stream()
                    .filter(item -> item.getId() != null)
                    .collect(Collectors.toList());

            //插入
            settlementItemMapper.insertBatch(createDO);
            // 更新
            settlementItemMapper.updateBatch(updateDO);
        }

        customerSettlementMapper.updateById(updateObj);
    }

    @Override
    public void deleteCustomerSettlement(Long id) {
        // 校验存在
        validateCustomerSettlementExists(id);
        // 删除
        customerSettlementMapper.deleteById(id);

        // 同步删除结算明细
        settlementItemMapper.delete(new LambdaQueryWrapperX<SettlementItemDO>()
                .eq(SettlementItemDO::getSettlementId, id));
    }

    private CustomerSettlementDO validateCustomerSettlementExists(Long id) {
        CustomerSettlementDO customerSettlement = customerSettlementMapper.selectById(id);
        if (customerSettlement == null) {
            throw exception(CUSTOMER_SETTLEMENT_NOT_EXISTS);
        }

        return customerSettlement;
    }

    @Override
    public CustomerSettlementDO getCustomerSettlement(Long id) {
        return customerSettlementMapper.selectById(id);
    }

    @Override
    public PageResult<CustomerSettlementDO> getCustomerSettlementPage(CustomerSettlementPageReqVO pageReqVO) {
        return customerSettlementMapper.selectPage(pageReqVO);
    }

    @Override
    public List<SettlementItemDO> getSettlementItemListBySettlementId(List<Long> ids, Integer businessType) {

        return settlementItemMapper.selectList(new LambdaQueryWrapperX<SettlementItemDO>()
                .inIfPresent(SettlementItemDO::getSettlementId, ids)
                .eqIfPresent(SettlementItemDO::getBusinessType, businessType));
    }

    @Override
    public void updateConfirm(Long id, Integer status) {
        // 校验存在
        validateCustomerSettlementExists(id);

        // 更新
        customerSettlementMapper.updateById(new CustomerSettlementDO()
                .setId(id)
                .setStatus(status));
    }

    @Override
    public StatisticsVO getCustomerSettlementTotal(CustomerSettlementPageReqVO pageReqVO) {

        return customerSettlementMapper.selectTotal(pageReqVO);
    }

    @Override
    public List<SettlementItemDTO> getDeductionItems(Long factoryId, String month) {
        return customerSettlementMapper.selectDeductionItems(factoryId, month);
    }
}