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

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.*;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.*;
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.delivery.event.DeliveryCompletedEvent;
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.util.List;

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

@Service
@Validated
public class DeliveryOrderServiceImpl implements DeliveryOrderService {

    @Resource
    private DeliveryOrderMapper deliveryOrderMapper;

    @Resource
    private DeliveryOrderVehicleMapper deliveryOrderVehicleMapper;

    @Resource
    private DeliveryTaskMapper deliveryTaskMapper;

    @Resource
    private DeliveryTaskVehicleMapper deliveryTaskVehicleMapper;

    @Resource
    private InspectionRecordService inspectionRecordService;

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createDeliveryOrder(DeliveryOrderSaveReqVO createReqVO) {
        // Get task info
        DeliveryTaskDO task = deliveryTaskMapper.selectById(createReqVO.getTaskId());
        if (task == null) {
            throw exception(DELIVERY_TASK_NOT_EXISTS);
        }
        if (task.getTaskStatus().equals(1)) {
            throw exception(DELIVERY_TASK_SUSPENDED);
        }

        // Generate order code
        String orderCode = task.getTaskCode() + "O0001";

        DeliveryOrderDO order = BeanUtils.toBean(createReqVO, DeliveryOrderDO.class);
        order.setOrderCode(orderCode);
        order.setTaskCode(task.getTaskCode());
        order.setContractId(task.getContractId());
        order.setContractCode(task.getContractCode());
        order.setProjectName(task.getProjectName());
        order.setCustomerId(task.getCustomerId());
        order.setCustomerName(task.getCustomerName());
        order.setStatus(0); // pending
        order.setEsignStatus(0);
        deliveryOrderMapper.insert(order);

        // Insert vehicles
        if (createReqVO.getVehicles() != null) {
            for (DeliveryOrderVehicleVO vehicleVO : createReqVO.getVehicles()) {
                DeliveryOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryOrderVehicleDO.class);
                vehicle.setOrderId(order.getId());
                deliveryOrderVehicleMapper.insert(vehicle);
            }

            // 从第一辆车的备车验车记录克隆交车验车记录
            DeliveryOrderVehicleVO firstVehicle = createReqVO.getVehicles().get(0);
            if (firstVehicle.getVehicleId() != null) {
                InspectionRecordDO prepareRecord = inspectionRecordService.getLatestRecord(
                        firstVehicle.getVehicleId(), InspectionSourceTypeEnum.PREPARE.getType());
                if (prepareRecord != null) {
                    Long inspectionRecordId = inspectionRecordService.cloneRecord(
                            prepareRecord.getId(), InspectionSourceTypeEnum.DELIVERY.getType(), order.getId());
                    deliveryOrderMapper.updateById(DeliveryOrderDO.builder()
                            .id(order.getId()).inspectionRecordId(inspectionRecordId).build());
                }
            }
        }

        return order.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDeliveryOrder(DeliveryOrderSaveReqVO updateReqVO) {
        DeliveryOrderDO order = validateDeliveryOrderExists(updateReqVO.getId());
        if (order.getStatus().equals(1)) {
            throw exception(DELIVERY_ORDER_ALREADY_COMPLETED);
        }

        DeliveryOrderDO updateObj = BeanUtils.toBean(updateReqVO, DeliveryOrderDO.class);
        deliveryOrderMapper.updateById(updateObj);

        // Update vehicles
        if (updateReqVO.getVehicles() != null) {
            deliveryOrderVehicleMapper.deleteByOrderId(updateReqVO.getId());
            for (DeliveryOrderVehicleVO vehicleVO : updateReqVO.getVehicles()) {
                DeliveryOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryOrderVehicleDO.class);
                vehicle.setOrderId(updateReqVO.getId());
                deliveryOrderVehicleMapper.insert(vehicle);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDeliveryOrder(Long id) {
        validateDeliveryOrderExists(id);
        deliveryOrderMapper.deleteById(id);
        deliveryOrderVehicleMapper.deleteByOrderId(id);
    }

    @Override
    public DeliveryOrderDO getDeliveryOrder(Long id) {
        return deliveryOrderMapper.selectById(id);
    }

    @Override
    public DeliveryOrderRespVO getDeliveryOrderDetail(Long id) {
        DeliveryOrderDO order = validateDeliveryOrderExists(id);
        DeliveryOrderRespVO respVO = BeanUtils.toBean(order, DeliveryOrderRespVO.class);
        List<DeliveryOrderVehicleDO> vehicles = deliveryOrderVehicleMapper.selectListByOrderId(id);
        respVO.setVehicles(BeanUtils.toBean(vehicles, DeliveryOrderVehicleVO.class));
        return respVO;
    }

    @Override
    public PageResult<DeliveryOrderDO> getDeliveryOrderPage(DeliveryOrderPageReqVO pageReqVO) {
        return deliveryOrderMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeDeliveryOrder(Long id) {
        DeliveryOrderDO order = validateDeliveryOrderExists(id);
        if (order.getStatus().equals(1)) {
            throw exception(DELIVERY_ORDER_ALREADY_COMPLETED);
        }

        // Update order status
        deliveryOrderMapper.updateById(DeliveryOrderDO.builder().id(id).status(1).build());

        // Mark task vehicles as delivered
        List<DeliveryOrderVehicleDO> orderVehicles = deliveryOrderVehicleMapper.selectListByOrderId(id);
        for (DeliveryOrderVehicleDO ov : orderVehicles) {
            deliveryTaskVehicleMapper.updateById(
                DeliveryTaskVehicleDO.builder()
                    .id(ov.getTaskVehicleId())
                    .isDelivered(true)
                    .build()
            );
        }

        // Check if all task vehicles are delivered, update task delivery status
        DeliveryTaskDO task = deliveryTaskMapper.selectById(order.getTaskId());
        if (task != null) {
            List<DeliveryTaskVehicleDO> taskVehicles = deliveryTaskVehicleMapper.selectListByTaskId(task.getId());
            boolean allDelivered = taskVehicles.stream().allMatch(v -> Boolean.TRUE.equals(v.getIsDelivered()));
            if (allDelivered) {
                deliveryTaskMapper.updateById(DeliveryTaskDO.builder().id(task.getId()).deliveryStatus(1).build());
            }
        }

        // Publish delivery completed events for each vehicle
        for (DeliveryOrderVehicleDO ov : orderVehicles) {
            eventPublisher.publishEvent(new DeliveryCompletedEvent(id, ov.getVehicleId()));
        }
    }

    private DeliveryOrderDO validateDeliveryOrderExists(Long id) {
        DeliveryOrderDO order = deliveryOrderMapper.selectById(id);
        if (order == null) {
            throw exception(DELIVERY_ORDER_NOT_EXISTS);
        }
        return order;
    }

}
