package cn.iocoder.yudao.module.energy.service.detail;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.energy.controller.admin.detail.vo.HydrogenDetailPageReqVO;
import cn.iocoder.yudao.module.energy.controller.admin.detail.vo.HydrogenDetailSaveReqVO;
import cn.iocoder.yudao.module.energy.dal.dataobject.detail.EnergyHydrogenDetailDO;
import cn.iocoder.yudao.module.energy.dal.dataobject.record.EnergyHydrogenRecordDO;
import cn.iocoder.yudao.module.energy.dal.dataobject.price.EnergyStationPriceDO;
import cn.iocoder.yudao.module.energy.dal.mysql.detail.EnergyHydrogenDetailMapper;
import cn.iocoder.yudao.module.energy.dal.mysql.record.EnergyHydrogenRecordMapper;
import cn.iocoder.yudao.module.energy.enums.AuditStatusEnum;
import cn.iocoder.yudao.module.energy.enums.CostBearerEnum;
import cn.iocoder.yudao.module.energy.enums.DeductionStatusEnum;
import cn.iocoder.yudao.module.energy.enums.PayMethodEnum;
import cn.iocoder.yudao.module.energy.event.DetailAuditPassedEvent;
import cn.iocoder.yudao.module.energy.service.price.EnergyStationPriceService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

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

@Service
@Validated
@Slf4j
public class HydrogenDetailServiceImpl implements HydrogenDetailService {

    @Resource
    private EnergyHydrogenDetailMapper detailMapper;
    @Resource
    private EnergyHydrogenRecordMapper recordMapper;
    @Resource
    private EnergyStationPriceService stationPriceService;
    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    public void updateDetail(HydrogenDetailSaveReqVO reqVO) {
        validateDetailExists(reqVO.getId());
        EnergyHydrogenDetailDO updateObj = new EnergyHydrogenDetailDO();
        updateObj.setId(reqVO.getId());
        if (reqVO.getCostPrice() != null) {
            updateObj.setCostPrice(reqVO.getCostPrice());
        }
        if (reqVO.getCustomerPrice() != null) {
            updateObj.setCustomerPrice(reqVO.getCustomerPrice());
        }
        if (reqVO.getRemark() != null) {
            updateObj.setRemark(reqVO.getRemark());
        }
        detailMapper.updateById(updateObj);
    }

    @Override
    public PageResult<EnergyHydrogenDetailDO> getDetailPage(HydrogenDetailPageReqVO pageReqVO) {
        return detailMapper.selectPage(pageReqVO);
    }

    @Override
    public EnergyHydrogenDetailDO getDetail(Long id) {
        return detailMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(Long id, Boolean approved, String remark) {
        EnergyHydrogenDetailDO detail = validateDetailExists(id);
        if (!AuditStatusEnum.PENDING.getStatus().equals(detail.getAuditStatus())) {
            throw exception(HYDROGEN_DETAIL_ALREADY_AUDITED);
        }
        Integer newStatus = approved ? AuditStatusEnum.APPROVED.getStatus() : AuditStatusEnum.REJECTED.getStatus();
        detailMapper.update(null, new LambdaUpdateWrapper<EnergyHydrogenDetailDO>()
                .set(EnergyHydrogenDetailDO::getAuditStatus, newStatus)
                .set(EnergyHydrogenDetailDO::getAuditRemark, remark)
                .eq(EnergyHydrogenDetailDO::getId, id));

        // If approved, publish event for deduction
        if (approved) {
            eventPublisher.publishEvent(new DetailAuditPassedEvent(
                    id, detail.getStationId(), detail.getCustomerId(),
                    detail.getContractId(), detail.getCustomerAmount()));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAudit(List<Long> ids, Boolean approved, String remark) {
        for (Long id : ids) {
            audit(id, approved, remark);
        }
    }

    @Override
    public void updateDeductionStatus(Long detailId, Integer status) {
        detailMapper.update(null, new LambdaUpdateWrapper<EnergyHydrogenDetailDO>()
                .set(EnergyHydrogenDetailDO::getDeductionStatus, status)
                .eq(EnergyHydrogenDetailDO::getId, detailId));
    }

    @Override
    public void updateBillId(List<Long> detailIds, Long billId) {
        if (detailIds == null || detailIds.isEmpty()) return;
        detailMapper.update(null, new LambdaUpdateWrapper<EnergyHydrogenDetailDO>()
                .set(EnergyHydrogenDetailDO::getBillId, billId)
                .in(EnergyHydrogenDetailDO::getId, detailIds));
    }

    @Override
    public void updateSettlementStatus(List<Long> detailIds, Integer status) {
        if (detailIds == null || detailIds.isEmpty()) return;
        detailMapper.update(null, new LambdaUpdateWrapper<EnergyHydrogenDetailDO>()
                .set(EnergyHydrogenDetailDO::getSettlementStatus, status)
                .in(EnergyHydrogenDetailDO::getId, detailIds));
    }

    private EnergyHydrogenDetailDO validateDetailExists(Long id) {
        EnergyHydrogenDetailDO detail = detailMapper.selectById(id);
        if (detail == null) {
            throw exception(HYDROGEN_DETAIL_NOT_EXISTS);
        }
        return detail;
    }
}
