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

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderVehicleDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderVehicleDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicle.VehicleBaseDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.vehiclemodel.VehicleModelDO;
import cn.iocoder.yudao.module.asset.dal.mysql.contract.ContractMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderVehicleMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderVehicleMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.vehicle.VehicleBaseMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.vehiclemodel.VehicleModelMapper;
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
import cn.iocoder.yudao.module.asset.service.inspection.InspectionTemplateService;
import cn.iocoder.yudao.module.asset.service.returnorder.event.ReturnApprovedEvent;
import cn.iocoder.yudao.module.asset.service.returnorder.listener.ReturnOrderBpmListener;
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 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.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

@Service
@Validated
@Slf4j
public class ReturnOrderServiceImpl implements ReturnOrderService {

    @Resource
    private ReturnOrderMapper returnOrderMapper;

    @Resource
    private ReturnOrderVehicleMapper returnOrderVehicleMapper;

    @Resource
    private DeliveryOrderMapper deliveryOrderMapper;

    @Resource
    private DeliveryOrderVehicleMapper deliveryOrderVehicleMapper;

    @Resource
    private ContractMapper contractMapper;

    @Resource
    private VehicleBaseMapper vehicleBaseMapper;

    @Resource
    private VehicleModelMapper vehicleModelMapper;

    @Resource
    private InspectionRecordMapper inspectionRecordMapper;

    @Resource
    private InspectionRecordService inspectionRecordService;

    @Resource
    private InspectionTemplateService inspectionTemplateService;

    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createReturnOrder(ReturnOrderSaveReqVO createReqVO) {
        // Generate order code: HC + timestamp
        String orderCode = "HC" + System.currentTimeMillis();

        ReturnOrderDO order = BeanUtils.toBean(createReqVO, ReturnOrderDO.class);
        order.setOrderCode(orderCode);
        order.setSourceType(1); // 手动创建
        order.setStatus(0); // pending inspection
        order.setApprovalStatus(0); // draft
        returnOrderMapper.insert(order);

        // Insert vehicles
        if (createReqVO.getVehicles() != null) {
            for (ReturnOrderVehicleVO vehicleVO : createReqVO.getVehicles()) {
                ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
                vehicle.setReturnOrderId(order.getId());
                returnOrderVehicleMapper.insert(vehicle);
            }
        }

        // Calculate total refund
        calculateTotalRefund(order.getId());

        return order.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateReturnOrder(ReturnOrderSaveReqVO updateReqVO) {
        ReturnOrderDO order = validateReturnOrderExists(updateReqVO.getId());
        if (order.getStatus().equals(2)) {
            throw exception(RETURN_ORDER_ALREADY_SETTLED);
        }

        ReturnOrderDO updateObj = BeanUtils.toBean(updateReqVO, ReturnOrderDO.class);
        returnOrderMapper.updateById(updateObj);

        // Update vehicles
        if (updateReqVO.getVehicles() != null) {
            returnOrderVehicleMapper.deleteByReturnOrderId(updateReqVO.getId());
            for (ReturnOrderVehicleVO vehicleVO : updateReqVO.getVehicles()) {
                ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
                vehicle.setReturnOrderId(updateReqVO.getId());
                returnOrderVehicleMapper.insert(vehicle);
            }
        }

        calculateTotalRefund(updateReqVO.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteReturnOrder(Long id) {
        validateReturnOrderExists(id);
        returnOrderMapper.deleteById(id);
        returnOrderVehicleMapper.deleteByReturnOrderId(id);
    }

    @Override
    public ReturnOrderDO getReturnOrder(Long id) {
        return returnOrderMapper.selectById(id);
    }

    @Override
    public ReturnOrderRespVO getReturnOrderDetail(Long id) {
        ReturnOrderDO order = validateReturnOrderExists(id);
        ReturnOrderRespVO respVO = BeanUtils.toBean(order, ReturnOrderRespVO.class);
        List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
        respVO.setVehicles(BeanUtils.toBean(vehicles, ReturnOrderVehicleVO.class));
        return respVO;
    }

    @Override
    public PageResult<ReturnOrderDO> getReturnOrderPage(ReturnOrderPageReqVO pageReqVO) {
        return returnOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public void completeInspection(Long id) {
        ReturnOrderDO order = validateReturnOrderExists(id);
        if (order.getStatus().equals(2)) {
            throw exception(RETURN_ORDER_ALREADY_SETTLED);
        }
        returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(1).build());
    }

    @Override
    public void settleReturnOrder(Long id) {
        ReturnOrderDO order = validateReturnOrderExists(id);
        if (order.getStatus().equals(2)) {
            throw exception(RETURN_ORDER_ALREADY_SETTLED);
        }
        returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(2).build());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createFromDelivery(Long deliveryOrderId, List<Long> vehicleIds) {
        // 查询交车单信息
        DeliveryOrderDO deliveryOrder = deliveryOrderMapper.selectById(deliveryOrderId);
        if (deliveryOrder == null) {
            throw exception(DELIVERY_ORDER_NOT_EXISTS);
        }

        // 创建还车单
        ReturnOrderDO order = new ReturnOrderDO();
        order.setOrderCode("HC" + System.currentTimeMillis());
        order.setSourceType(1); // 手动（从交车单创建）
        order.setDeliveryOrderId(deliveryOrderId);
        order.setContractId(deliveryOrder.getContractId());
        order.setContractCode(deliveryOrder.getContractCode());
        order.setProjectName(deliveryOrder.getProjectName());
        order.setCustomerId(deliveryOrder.getCustomerId());
        order.setCustomerName(deliveryOrder.getCustomerName());
        order.setStatus(0); // 待验车
        order.setApprovalStatus(0); // 草稿
        returnOrderMapper.insert(order);

        // 查询交车单车辆，筛选指定的 vehicleIds
        List<DeliveryOrderVehicleDO> deliveryVehicles = deliveryOrderVehicleMapper.selectListByOrderId(deliveryOrderId);
        for (DeliveryOrderVehicleDO dv : deliveryVehicles) {
            if (vehicleIds.contains(dv.getVehicleId())) {
                ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
                vehicle.setReturnOrderId(order.getId());
                vehicle.setVehicleId(dv.getVehicleId());
                vehicle.setPlateNo(dv.getPlateNo());
                vehicle.setVin(dv.getVin());
                vehicle.setBrand(dv.getBrand());
                vehicle.setModel(dv.getModel());
                returnOrderVehicleMapper.insert(vehicle);
            }
        }

        return order.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createFromReplacement(Long replacementId, Long contractId, Long vehicleId) {
        // 查询合同信息
        ContractDO contract = contractMapper.selectById(contractId);
        if (contract == null) {
            throw exception(CONTRACT_NOT_EXISTS);
        }

        // 创建还车单
        ReturnOrderDO order = new ReturnOrderDO();
        order.setOrderCode("HC" + System.currentTimeMillis());
        order.setSourceType(2); // 替换车触发
        order.setSourceId(replacementId);
        order.setContractId(contractId);
        order.setContractCode(contract.getContractCode());
        order.setProjectName(contract.getProjectName());
        order.setCustomerId(contract.getCustomerId());
        order.setCustomerName(contract.getCustomerName());
        order.setStatus(0); // 待验车
        order.setApprovalStatus(0); // 草稿
        returnOrderMapper.insert(order);

        // 创建还车车辆（原车辆）
        VehicleBaseDO vehicleBase = vehicleBaseMapper.selectById(vehicleId);
        if (vehicleBase == null) {
            throw exception(VEHICLE_NOT_EXISTS);
        }

        ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
        vehicle.setReturnOrderId(order.getId());
        vehicle.setVehicleId(vehicleId);
        vehicle.setPlateNo(vehicleBase.getPlateNo());
        vehicle.setVin(vehicleBase.getVin());

        // 通过车型ID查询品牌和型号
        if (vehicleBase.getVehicleModelId() != null) {
            VehicleModelDO vehicleModel = vehicleModelMapper.selectById(vehicleBase.getVehicleModelId());
            if (vehicleModel != null) {
                vehicle.setBrand(vehicleModel.getBrand());
                vehicle.setModel(vehicleModel.getModel());
            }
        }

        returnOrderVehicleMapper.insert(vehicle);

        return order.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long startVehicleInspection(Long returnOrderVehicleId) {
        // 查找还车车辆
        ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
        if (vehicle == null) {
            throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
        }
        if (vehicle.getInspectionRecordId() != null) {
            throw exception(RETURN_ORDER_INSPECTION_ALREADY_STARTED);
        }

        Long inspectionRecordId;

        // 尝试查找最新的交车验车记录进行克隆
        InspectionRecordDO latestRecord = inspectionRecordService.getLatestRecord(
                vehicle.getVehicleId(), InspectionSourceTypeEnum.DELIVERY.getType());

        if (latestRecord != null) {
            // 克隆交车验车记录
            inspectionRecordId = inspectionRecordService.cloneRecord(
                    latestRecord.getId(),
                    InspectionSourceTypeEnum.RETURN.getType(),
                    returnOrderVehicleId);
        } else {
            // 没有交车记录，尝试匹配模板创建新记录
            InspectionTemplateDO template = inspectionTemplateService.matchTemplate(
                    InspectionSourceTypeEnum.RETURN.getType(), null);
            if (template == null) {
                throw exception(INSPECTION_TEMPLATE_MATCH_FAILED);
            }
            inspectionRecordId = inspectionRecordService.createRecord(
                    template.getId(),
                    InspectionSourceTypeEnum.RETURN.getType(),
                    returnOrderVehicleId,
                    vehicle.getVehicleId());
        }

        // 更新还车车辆的验车记录ID
        ReturnOrderVehicleDO updateObj = new ReturnOrderVehicleDO();
        updateObj.setId(returnOrderVehicleId);
        updateObj.setInspectionRecordId(inspectionRecordId);
        returnOrderVehicleMapper.updateById(updateObj);

        return inspectionRecordId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeVehicleInspection(Long returnOrderVehicleId) {
        // 查找还车车辆
        ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
        if (vehicle == null) {
            throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
        }
        if (vehicle.getInspectionRecordId() == null) {
            throw exception(RETURN_ORDER_INSPECTION_NOT_STARTED);
        }

        // 完成验车记录
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String inspectorName = userId != null ? String.valueOf(userId) : "system";
        inspectionRecordService.completeRecord(vehicle.getInspectionRecordId(), inspectorName);

        // 检查该还车单的所有车辆是否都完成了验车
        List<ReturnOrderVehicleDO> allVehicles = returnOrderVehicleMapper.selectListByReturnOrderId(vehicle.getReturnOrderId());
        boolean allCompleted = allVehicles.stream().allMatch(v -> {
            if (v.getInspectionRecordId() == null) {
                return false;
            }
            // 当前正在完成的车辆视为已完成
            if (v.getId().equals(returnOrderVehicleId)) {
                return true;
            }
            // 检查验车记录状态（2=已完成）
            InspectionRecordDO record = inspectionRecordMapper.selectById(v.getInspectionRecordId());
            return record != null && Integer.valueOf(2).equals(record.getStatus());
        });

        if (allCompleted) {
            // 所有车辆验车完成，更新还车单状态
            returnOrderMapper.updateById(ReturnOrderDO.builder()
                    .id(vehicle.getReturnOrderId())
                    .status(1) // 验车完成
                    .build());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitApproval(Long id) {
        ReturnOrderDO order = validateReturnOrderExists(id);

        // 校验状态：验车完成才能提交审批
        if (!Integer.valueOf(1).equals(order.getStatus())) {
            throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
        }
        // 校验审批状态：草稿、已驳回、已撤回才能提交
        if (order.getApprovalStatus() != null && order.getApprovalStatus() == 1) {
            throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
        }

        // 创建流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("orderCode", order.getOrderCode());
        variables.put("contractCode", order.getContractCode());
        variables.put("customerName", order.getCustomerName());

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

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

        // 更新审批状态
        ReturnOrderDO updateObj = new ReturnOrderDO();
        updateObj.setId(id);
        updateObj.setApprovalStatus(1); // 审批中
        updateObj.setBpmInstanceId(processInstanceId);
        returnOrderMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawApproval(Long id) {
        ReturnOrderDO order = validateReturnOrderExists(id);

        // 校验审批状态：只有审批中才能撤回
        if (!Integer.valueOf(1).equals(order.getApprovalStatus())) {
            throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_WITHDRAW);
        }

        // 更新审批状态
        ReturnOrderDO updateObj = new ReturnOrderDO();
        updateObj.setId(id);
        updateObj.setApprovalStatus(4); // 已撤回
        returnOrderMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateApprovalStatus(Long id, Integer bpmStatus) {
        ReturnOrderDO order = validateReturnOrderExists(id);

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

        if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmStatus)) {
            updateObj.setApprovalStatus(2); // 审批通过
            returnOrderMapper.updateById(updateObj);

            // 发布审批通过事件
            List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
            List<Long> vehicleIds = vehicles.stream()
                    .map(ReturnOrderVehicleDO::getVehicleId)
                    .collect(Collectors.toList());
            eventPublisher.publishEvent(new ReturnApprovedEvent(id, vehicleIds));
        } else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmStatus)) {
            updateObj.setApprovalStatus(3); // 审批拒绝
            returnOrderMapper.updateById(updateObj);
        } else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmStatus)) {
            updateObj.setApprovalStatus(4); // 已撤回
            returnOrderMapper.updateById(updateObj);
        }
    }

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

    private ReturnOrderDO validateReturnOrderExists(Long id) {
        ReturnOrderDO order = returnOrderMapper.selectById(id);
        if (order == null) {
            throw exception(RETURN_ORDER_NOT_EXISTS);
        }
        return order;
    }

    private void calculateTotalRefund(Long orderId) {
        ReturnOrderDO order = returnOrderMapper.selectById(orderId);
        if (order == null) return;

        List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(orderId);
        BigDecimal totalHydrogenRefund = vehicles.stream()
                .map(v -> v.getHydrogenRefundAmount() != null ? v.getHydrogenRefundAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal depositRefund = order.getDepositRefund() != null ? order.getDepositRefund() : BigDecimal.ZERO;
        BigDecimal otherCharges = order.getOtherCharges() != null ? order.getOtherCharges() : BigDecimal.ZERO;
        BigDecimal totalRefund = depositRefund.add(totalHydrogenRefund).subtract(otherCharges);

        returnOrderMapper.updateById(ReturnOrderDO.builder()
                .id(orderId)
                .hydrogenRefund(totalHydrogenRefund)
                .totalRefundAmount(totalRefund)
                .build());
    }

}
