package cn.iocoder.yudao.module.asset.service.replacement;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementPageReqVO;
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementSaveReqVO;
import cn.iocoder.yudao.module.asset.convert.replacement.VehicleReplacementConvert;
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
import cn.iocoder.yudao.module.asset.dal.mysql.replacement.VehicleReplacementMapper;
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementStatusEnum;
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementTypeEnum;
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementApprovedEvent;
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementReturnConfirmedEvent;
import cn.iocoder.yudao.module.asset.service.replacement.listener.ReplacementBpmListener;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
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 jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

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

/**
 * 替换车申请 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class VehicleReplacementServiceImpl implements VehicleReplacementService {

    @Resource
    private VehicleReplacementMapper replacementMapper;

    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createReplacement(VehicleReplacementSaveReqVO createReqVO) {
        // 转换并插入
        VehicleReplacementDO replacement = VehicleReplacementConvert.INSTANCE.convert(createReqVO);

        // 生成替换单编码
        replacement.setReplacementCode(generateReplacementCode());

        // 设置初始状态
        replacement.setStatus(ReplacementStatusEnum.DRAFT.getStatus());
        replacement.setApprovalStatus(0);

        replacementMapper.insert(replacement);
        return replacement.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateReplacement(VehicleReplacementSaveReqVO updateReqVO) {
        // 校验存在
        VehicleReplacementDO existing = validateReplacementExists(updateReqVO.getId());

        // 校验状态：只有草稿、审批驳回状态才能修改
        if (!ReplacementStatusEnum.DRAFT.getStatus().equals(existing.getStatus())
                && !ReplacementStatusEnum.REJECTED.getStatus().equals(existing.getStatus())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_UPDATE);
        }

        // 转换并更新
        VehicleReplacementDO updateObj = VehicleReplacementConvert.INSTANCE.convert(updateReqVO);
        replacementMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteReplacement(Long id) {
        // 校验存在
        VehicleReplacementDO replacement = validateReplacementExists(id);

        // 校验状态：只有草稿状态才能删除
        if (!ReplacementStatusEnum.DRAFT.getStatus().equals(replacement.getStatus())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_DELETE);
        }

        replacementMapper.deleteById(id);
    }

    @Override
    public VehicleReplacementDO getReplacement(Long id) {
        return replacementMapper.selectById(id);
    }

    @Override
    public PageResult<VehicleReplacementDO> getReplacementPage(VehicleReplacementPageReqVO pageReqVO) {
        return replacementMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitApproval(Long id) {
        // 校验存在
        VehicleReplacementDO replacement = validateReplacementExists(id);

        // 校验状态：只有草稿、审批驳回状态才能提交审批
        if (!ReplacementStatusEnum.DRAFT.getStatus().equals(replacement.getStatus())
                && !ReplacementStatusEnum.REJECTED.getStatus().equals(replacement.getStatus())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_SUBMIT);
        }

        // 创建流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("replacementCode", replacement.getReplacementCode());
        variables.put("replacementType", replacement.getReplacementType());
        variables.put("contractCode", replacement.getContractCode());
        variables.put("customerName", replacement.getCustomerName());
        variables.put("originalPlateNo", replacement.getOriginalPlateNo());
        variables.put("newPlateNo", replacement.getNewPlateNo());

        // 创建流程实例
        BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
        reqDTO.setProcessDefinitionKey(ReplacementBpmListener.PROCESS_KEY);
        reqDTO.setBusinessKey(String.valueOf(id));
        reqDTO.setVariables(variables);

        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, reqDTO).getData();

        // 更新状态
        VehicleReplacementDO updateObj = new VehicleReplacementDO();
        updateObj.setId(id);
        updateObj.setStatus(ReplacementStatusEnum.APPROVING.getStatus());
        updateObj.setBpmInstanceId(processInstanceId);
        replacementMapper.updateById(updateObj);

        return processInstanceId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawApproval(Long id) {
        // 校验存在
        VehicleReplacementDO replacement = validateReplacementExists(id);

        // 校验状态：只有审批中状态才能撤回
        if (!ReplacementStatusEnum.APPROVING.getStatus().equals(replacement.getStatus())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_WITHDRAW);
        }

        // 更新状态
        VehicleReplacementDO updateObj = new VehicleReplacementDO();
        updateObj.setId(id);
        updateObj.setStatus(ReplacementStatusEnum.WITHDRAWN.getStatus());
        replacementMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateApprovalStatus(Long id, Integer bpmStatus) {
        // 校验存在
        VehicleReplacementDO replacement = validateReplacementExists(id);

        VehicleReplacementDO updateObj = new VehicleReplacementDO();
        updateObj.setId(id);

        if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmStatus)) {
            // 审批通过 → 直接进入执行中
            updateObj.setStatus(ReplacementStatusEnum.EXECUTING.getStatus());
            updateObj.setActualDate(LocalDate.now());
            replacementMapper.updateById(updateObj);

            // 发布审批通过事件
            eventPublisher.publishEvent(new ReplacementApprovedEvent(
                    replacement.getId(),
                    replacement.getReplacementType(),
                    replacement.getContractId(),
                    replacement.getOriginalVehicleId()
            ));

            // 永久替换审批通过后直接完成
            if (ReplacementTypeEnum.PERMANENT.getType().equals(replacement.getReplacementType())) {
                VehicleReplacementDO completeObj = new VehicleReplacementDO();
                completeObj.setId(id);
                completeObj.setStatus(ReplacementStatusEnum.COMPLETED.getStatus());
                replacementMapper.updateById(completeObj);
            }
        } else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmStatus)) {
            updateObj.setStatus(ReplacementStatusEnum.REJECTED.getStatus());
            replacementMapper.updateById(updateObj);
        } else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmStatus)) {
            updateObj.setStatus(ReplacementStatusEnum.WITHDRAWN.getStatus());
            replacementMapper.updateById(updateObj);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReturn(Long id) {
        // 校验存在
        VehicleReplacementDO replacement = validateReplacementExists(id);

        // 校验状态：只有执行中状态才能确认换回
        if (!ReplacementStatusEnum.EXECUTING.getStatus().equals(replacement.getStatus())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM);
        }

        // 校验类型：只有临时替换才能确认换回
        if (!ReplacementTypeEnum.TEMPORARY.getType().equals(replacement.getReplacementType())) {
            throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM);
        }

        // 更新状态
        VehicleReplacementDO updateObj = new VehicleReplacementDO();
        updateObj.setId(id);
        updateObj.setStatus(ReplacementStatusEnum.COMPLETED.getStatus());
        updateObj.setActualReturnDate(LocalDate.now());
        replacementMapper.updateById(updateObj);

        // 发布换回确认事件
        eventPublisher.publishEvent(new ReplacementReturnConfirmedEvent(
                replacement.getId(),
                replacement.getOriginalVehicleId()
        ));
    }

    // ==================== 私有方法 ====================

    /**
     * 校验替换车申请是否存在
     */
    private VehicleReplacementDO validateReplacementExists(Long id) {
        VehicleReplacementDO replacement = replacementMapper.selectById(id);
        if (replacement == null) {
            throw exception(VEHICLE_REPLACEMENT_NOT_EXISTS);
        }
        return replacement;
    }

    /**
     * 生成替换单编码
     */
    private String generateReplacementCode() {
        // 格式：TH-yyyyMMdd-NNN
        String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "TH-" + dateStr + "-";

        String maxCode = replacementMapper.selectMaxReplacementCodeByPrefix(prefix);

        int nextSeq = 1;
        if (maxCode != null && maxCode.startsWith(prefix)) {
            try {
                String seqStr = maxCode.substring(prefix.length());
                nextSeq = Integer.parseInt(seqStr) + 1;
            } catch (Exception e) {
                log.warn("解析替换单编码失败: {}", maxCode, e);
            }
        }

        return prefix + String.format("%03d", nextSeq);
    }

}
