package cn.iocoder.foodnexus.module.order.service.checktask;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.PurchaseOrderSplitEvent;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderService;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.dal.dataobject.checktaskitems.CheckTaskItemsDO;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.module.order.dal.mysql.checktaskitems.CheckTaskItemsMapper;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRecordEvent;
import cn.iocoder.foodnexus.module.order.enums.CheckTaskStatus;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.service.checktaskitems.CheckTaskItemsService;
import cn.iocoder.foodnexus.module.order.service.customerorder.CustomerOrderService;
import cn.iocoder.foodnexus.module.product.api.ProductSpuApi;
import cn.iocoder.foodnexus.module.product.api.category.ProductCategoryApi;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.category.ProductCategoryService;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.util.GenCodeUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import cn.iocoder.foodnexus.module.order.controller.admin.checktask.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.checktask.CheckTaskDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;

import cn.iocoder.foodnexus.module.order.dal.mysql.checktask.CheckTaskMapper;

import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;

/**
 * 来料质检 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
@Slf4j
public class CheckTaskServiceImpl implements CheckTaskService {

    @Resource
    private CheckTaskMapper checkTaskMapper;

    @Autowired
    private CheckTaskItemsMapper checkTaskItemsMapper;

    @Autowired
    private CheckTaskItemsService checkTaskItemsService;

    @Autowired
    @Lazy
    private ErpPurchaseOrderService purchaseOrderService;

    @Autowired
    private ProductSpuService productSpuService;

    @Autowired
    private ProductCategoryService productCategoryService;

    @Autowired
    @Lazy
    private CustomerOrderRecordApi orderRecordApi;

    @Autowired
    @Lazy
    private CustomerOrderService customerOrderService;

    @Autowired
    private GenCodeUtils genCodeUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCheckTask(CheckTaskSaveReqVO createReqVO) {
        // 插入
        CheckTaskDO checkTask = BeanUtils.toBean(createReqVO, CheckTaskDO.class);
        checkTaskMapper.insert(checkTask);

        Long id = checkTask.getId();
        for (CheckTaskItemsSaveReqVO item : createReqVO.getItems()) {
            item.setCheckTaskId(id);
            checkTaskItemsService.createCheckTaskItems(item);
        }

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

    @Override
    public void updateCheckTask(CheckTaskSaveReqVO updateReqVO) {
        // 校验存在
        validateCheckTaskExists(updateReqVO.getId());
        // 更新
        CheckTaskDO updateObj = BeanUtils.toBean(updateReqVO, CheckTaskDO.class);
        checkTaskMapper.updateById(updateObj);
    }

    @Override
    public void deleteCheckTask(Long id) {
        // 校验存在
        validateCheckTaskExists(id);
        // 删除
        checkTaskMapper.deleteById(id);
    }

    @Override
        public void deleteCheckTaskListByIds(List<Long> ids) {
        // 删除
        checkTaskMapper.deleteByIds(ids);
        }


    private void validateCheckTaskExists(Long id) {
        if (checkTaskMapper.selectById(id) == null) {
            throw exception(CHECK_TASK_NOT_EXISTS);
        }
    }

    @Override
    public CheckTaskDO getCheckTask(Long id) {
        return checkTaskMapper.selectById(id);
    }

    @Override
    public PageResult<CheckTaskDO> getCheckTaskPage(CheckTaskPageReqVO pageReqVO) {
        return checkTaskMapper.selectPage(pageReqVO);
    }

    /**
     * 质检
     *
     * @param updateReqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void check(CheckTaskCheckReqVO updateReqVO) {
        CheckTaskDO checkTaskDO = checkTaskMapper.selectById(updateReqVO.getId());
        if (checkTaskDO == null) {
            throw exception(CHECK_TASK_NOT_EXISTS);
        }
        if (CheckTaskStatus.NORMAL.getKey().equals(updateReqVO.getStatus())) {
            throw exception(CHECK_TASK_STATUS_ERROR);
        }

        checkTaskMapper.update(Wrappers.<CheckTaskDO>lambdaUpdate()
                .set(CheckTaskDO::getRemark, updateReqVO.getRemark())
                .set(CheckTaskDO::getFiles, updateReqVO.getFiles())
                .set(CheckTaskDO::getCheckTime, LocalDateTime.now())
                .set(CheckTaskDO::getCheckUserId, SecurityFrameworkUtils.getLoginUserId())
                .eq(CheckTaskDO::getId, updateReqVO.getId()));

        List<CheckTaskItemsDO> updateItems = BeanUtils.toBean(updateReqVO.getItems(), CheckTaskItemsDO.class);
        checkTaskItemsMapper.updateById(updateItems);

        if (CheckTaskStatus.NORMAL.getKey().equals(updateReqVO.getStatus())) {
            // 查询关联的客户订单
            CustomerOrderDO customerOrder = customerOrderService.getCustomerOrder(checkTaskDO.getCustomerOrderId());
            String warehouseName = Optional.ofNullable(customerOrder.getWarehouseInfo()).map(WarehouseInfo::getName).orElse("");

            CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
            event.setOrderStatus(CustomerOrderStatus.WAREHOUSE_INSPECTION);
            event.setSupplierId(checkTaskDO.getSupplierId());
            event.setCustomerOrderId(checkTaskDO.getCustomerOrderId());
            event.setCopyWriter(CommonUtil.asList(warehouseName, updateReqVO.getFiles()));
            orderRecordApi.recordEvent(event);
        }
    }


    @Async
    @TransactionalEventListener(classes = CheckTaskCreateEvent.class, phase = TransactionPhase.AFTER_COMMIT)
    public void createCheckTask(CheckTaskCreateEvent event) {
        log.info("来料质检创建事件:{}", event);
        if (CommonUtil.isEmpty(event) || CommonUtil.isEmpty(event.getSupplierOrderId())) {
            return ;
        }
        ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(event.getSupplierOrderId());
        List<ErpPurchaseOrderItemDO> purchaseOrderItems = purchaseOrderService.getPurchaseOrderItemListByOrderId(event.getSupplierOrderId());

        this.createCheckTask(this.transform(purchaseOrder, purchaseOrderItems));
    }

    private CheckTaskSaveReqVO transform(ErpPurchaseOrderDO purchaseOrder, List<ErpPurchaseOrderItemDO> purchaseOrderItems) {
        CheckTaskSaveReqVO checkTask = new CheckTaskSaveReqVO();
        if (CommonUtil.isEmpty(purchaseOrder)) {
            throw exception(CHECK_TASK_CREATE_ERROR);
        }
        if (CommonUtil.isEmpty(purchaseOrderItems)) {
            throw exception(CHECK_TASK_CREATE_ERROR);
        }

        checkTask.setNo(genCodeUtils.createAmBatch("LLZJ"));
        checkTask.setStatus(CheckTaskStatus.TO_BE_CHECK.getKey());
        checkTask.setSupplierId(checkTask.getSupplierId());
        checkTask.setPurchaseOrderId(purchaseOrder.getId());
        checkTask.setCustomerOrderId(purchaseOrder.getCustomerOrderId());
        checkTask.setCustomerId(purchaseOrderItems.get(0).getCustomerId());
        checkTask.setArrivalTime(LocalDateTime.now());

        Map<Long, ProductSpuDO> spuMap = productSpuService.getSpuMap(CommonUtil.listConvertSet(purchaseOrderItems,
                ErpPurchaseOrderItemDO::getProductId));
        checkTask.setItems(CommonUtil.listConvert(purchaseOrderItems, purchaseOrderItem -> {
            CheckTaskItemsSaveReqVO item = new CheckTaskItemsSaveReqVO();
            ProductSpuDO productSpuDO = spuMap.get(purchaseOrderItem.getProductId());
            item.setProductId(purchaseOrderItem.getProductId());
            item.setCategoryId(productSpuDO.getCategoryId());
            item.setCategoryName(productCategoryService.queryNameById(productSpuDO.getCategoryId()));
            item.setPicUrl(productSpuDO.getPicUrl());
            item.setCheckCount(purchaseOrderItem.getCount());
            item.setUnitName(purchaseOrderItem.getProductUnit());
            item.setCheckResult(CheckTaskStatus.TO_BE_CHECK.getKey());
            return item;
        }));

        return checkTask;
    }

}