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

import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
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.dal.mysql.purchase.ErpPurchaseOrderItemMapper;
import cn.iocoder.foodnexus.module.erp.dal.mysql.purchase.ErpPurchaseOrderMapper;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseInService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOrderService;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.scoringweight.ScoringWeightDO;
import cn.iocoder.foodnexus.module.operations.service.scoringweight.ScoringWeightService;
import cn.iocoder.foodnexus.module.order.api.CheckTaskApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.controller.admin.orderScore.vo.OrderScoreSaveReqVO;
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.framework.common.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.order.service.orderScore.OrderScoreService;
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.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.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.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.module.order.enums.ErrorCodeConstants.*;

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

    @Resource
    private CheckTaskMapper checkTaskMapper;

    @Autowired
    private CheckTaskItemsMapper checkTaskItemsMapper;

    @Autowired
    private CheckTaskItemsService checkTaskItemsService;

    @Autowired
    @Lazy
    private ErpPurchaseOrderService purchaseOrderService;

    @Autowired
    @Lazy
    private ErpPurchaseOrderMapper purchaseOrderMapper;

    @Autowired
    private ErpPurchaseOrderItemMapper purchaseOrderItemMapper;

    @Autowired
    private ProductSpuService productSpuService;

    @Autowired
    private ProductCategoryService productCategoryService;

    @Autowired
    @Lazy
    private CustomerOrderRecordApi orderRecordApi;

    @Autowired
    @Lazy
    private CustomerOrderService customerOrderService;

    @Autowired
    @Lazy
    private ErpSaleOrderService saleOrderService;

    @Autowired
    private ScoringWeightService scoringWeightService;

    @Autowired
    private OrderScoreService orderScoreService;
    
    @Autowired
    private ErpPurchaseInService purchaseInService;

    @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(checkTaskDO.getStatus())) {
            throw exception(CHECK_TASK_STATUS_ERROR);
        }

        ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(checkTaskDO.getPurchaseOrderId());
        if (CommonUtil.isEmpty(purchaseOrder)) {
            throw exception(CHECK_TASK_PURCHASE_ORDER_NOT_EXISTS);
        }
        if (!Objects.equals(purchaseOrder.getDeliveryStatus(), ErpDeliveryStatus.ARRIVAL.getStatus())) {
            throw exception(CHECK_TASK_PURCHASE_ORDER_STATUS_ERROR);
        }

        if (CheckTaskStatus.NORMAL.getKey().equals(updateReqVO.getStatus())) {
            purchaseOrderMapper.update(Wrappers.<ErpPurchaseOrderDO>lambdaUpdate()
                    .set(ErpPurchaseOrderDO::getCheckTaskStatus, CheckTaskStatus.NORMAL.getKey())
                    .eq(ErpPurchaseOrderDO::getId, purchaseOrder.getId()));
        }

        LambdaUpdateWrapper<CheckTaskDO> updateWrapper = Wrappers.<CheckTaskDO>lambdaUpdate()
                .set(CheckTaskDO::getRemark, updateReqVO.getRemark())
                .set(CheckTaskDO::getFiles, updateReqVO.getFiles())
                .set(CheckTaskDO::getCheckTime, LocalDateTime.now())
                .set(CheckTaskDO::getCheckUserId, SecurityFrameworkUtils.getLoginUserId())
                .set(CheckTaskDO::getStatus, updateReqVO.getStatus())
                .eq(CheckTaskDO::getId, updateReqVO.getId());
        if (CommonUtil.isNotEmpty(updateReqVO.getScore()) && CommonUtil.isNotBlank(updateReqVO.getScore().getScoreRemark())) {
            updateWrapper.set(CheckTaskDO::getScoreRemark, updateReqVO.getScore().getScoreRemark());
        }
        checkTaskMapper.update(updateWrapper);

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

        // 根据采购订单判断是否已经完成全部的质检，完成则新建配货单(销售订单)
        Long purchaseOrderCount = purchaseOrderMapper.selectCount(Wrappers.<ErpPurchaseOrderDO>lambdaQuery()
                .eq(ErpPurchaseOrderDO::getCustomerOrderId, checkTaskDO.getCustomerOrderId()));
        Long checkTaskCount = checkTaskMapper.selectCount(Wrappers.<CheckTaskDO>lambdaQuery()
                .eq(CheckTaskDO::getCustomerOrderId, checkTaskDO.getCustomerOrderId())
                .eq(CheckTaskDO::getStatus, CheckTaskStatus.NORMAL));
        if (Objects.equals(purchaseOrderCount, checkTaskCount)) {
            saleOrderService.createByCustomerOrderId(checkTaskDO.getCustomerOrderId());
        }

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

            List<ErpPurchaseOrderItemDO> purchaseOrderItems = purchaseOrderItemMapper.selectList(Wrappers.<ErpPurchaseOrderItemDO>lambdaQuery()
                    .eq(ErpPurchaseOrderItemDO::getOrderId, purchaseOrder.getId()));

            JSONArray fileUrlArray = new JSONArray();
            if (CommonUtil.isNotBlank(updateReqVO.getFiles())) {
                fileUrlArray.addAll(JSONArray.parseArray(updateReqVO.getFiles()));
            }
            purchaseOrderItems.forEach(purchaseOrderItem -> {
                if (CommonUtil.isNotBlank(purchaseOrderItem.getAnnex())) {
                    fileUrlArray.addAll(JSONArray.parseArray(purchaseOrderItem.getAnnex()));
                }
            });

            CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
            event.setOrderStatus(CustomerOrderStatus.WAREHOUSE_INSPECTION);
            event.setSupplierId(checkTaskDO.getSupplierId());
            event.setCustomerOrderId(checkTaskDO.getCustomerOrderId());
            event.setCopyWriter(CommonUtil.asList(warehouseName, fileUrlArray.toJSONString()));
            orderRecordApi.recordEvent(event);
            
            // 采购入库审核成功
            purchaseInService.updatePurchaseInStatusByPurchaseOrderId(checkTaskDO.getPurchaseOrderId(), ErpAuditStatus.APPROVE);

        } else if (CheckTaskStatus.ABNORMAL.getKey().equals(updateReqVO.getStatus())) {
            purchaseOrderService.abnormalPurchaseOrder(checkTaskDO.getPurchaseOrderId());
        }

        if (CommonUtil.isNotEmpty(updateReqVO.getScore())) {
            this.score(checkTaskDO, updateReqVO.getScore());
        }
    }

    @Override
    public CheckTaskSupplierScoreRespVO queryScore(Long id) {
        CheckTaskSupplierScoreRespVO result = new CheckTaskSupplierScoreRespVO();
        CheckTaskDO checkTask = this.getCheckTask(id);
        if (CommonUtil.isEmpty(checkTask)) {
            throw exception(CHECK_TASK_NOT_EXISTS);
        }
        result.setRemark(checkTask.getRemark());
        List<ScoringWeightDO> scoringWeightDOS = scoringWeightService.queryByUserSystem(UserSystemEnum.OPER);
        result.setItems(CommonUtil.listConvert(scoringWeightDOS, item -> {
            CheckTaskSupplierScoreRespVO.Item resultItem = new CheckTaskSupplierScoreRespVO.Item();
            resultItem.setScoreId(item.getId());
            resultItem.setScoreName(item.getScoreName());
            resultItem.setScore(orderScoreService.queryScore(id, item.getId()));
            return resultItem;
        }));

        return result;
    }

    @Override
    public CheckTaskDO queryScorebyPurchaseOrderId(Long purchaseOrderId) {
        return checkTaskMapper.selectOne(Wrappers.<CheckTaskDO>lambdaQuery()
                .eq(CheckTaskDO::getPurchaseOrderId, purchaseOrderId)
                .orderByDesc(CheckTaskDO::getId)
                .last("LIMIT 1"));
    }

    public void score(CheckTaskDO checkTaskDO, CheckTaskSupplierScoreReqVO reqVO) {
        Long id = checkTaskDO.getId();
        if (CommonUtil.isNotEmpty(reqVO.getItems())) {
            orderScoreService.deleteByOrderId(id);
            reqVO.getItems().forEach(item -> {
                ScoringWeightDO scoringWeight = scoringWeightService.getScoringWeight(item.getScoreId());
                OrderScoreSaveReqVO saveReqVO = new OrderScoreSaveReqVO();
                saveReqVO.setOrderId(id);
                saveReqVO.setScoreId(item.getScoreId());
                saveReqVO.setScoreName(scoringWeight.getScoreName());
                saveReqVO.setSupplierId(checkTaskDO.getSupplierId());
                saveReqVO.setCustomerId(checkTaskDO.getCustomerId());
                saveReqVO.setScore(item.getScore());
                saveReqVO.setSort(scoringWeight.getSort());
                orderScoreService.createScore(saveReqVO);
            });
        }
    }

    @Override
    @Async
    public void createByPurchaseOrderId(Long purchaseOrderId) {
        log.info("来料质检创建:{}", purchaseOrderId);
        ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(purchaseOrderId);
        List<ErpPurchaseOrderItemDO> purchaseOrderItems = purchaseOrderService.getPurchaseOrderItemListByOrderId(purchaseOrderId);

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

    @Override
    public Map<Long, String> getCheckResultMapByPurchaseOrderItemIds(Collection<Long> purchaseOrderItemIds) {
        if (CommonUtil.isEmpty(purchaseOrderItemIds)) {
            return new HashMap<>(1);
        }
        List<CheckTaskItemsDO> checkTaskItemsDOS = checkTaskItemsMapper.selectList(Wrappers.<CheckTaskItemsDO>lambdaQuery()
                .in(CheckTaskItemsDO::getPurchaseOrderItemId, purchaseOrderItemIds));
        return CommonUtil.listConvertMap(checkTaskItemsDOS, CheckTaskItemsDO::getPurchaseOrderItemId, CheckTaskItemsDO::getCheckResult);
    }

    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);
        }

        CustomerOrderDO customerOrder = customerOrderService.getCustomerOrder(purchaseOrder.getCustomerOrderId());
        checkTask.setNo(genCodeUtils.createAmBatch("LLZJ"));
        checkTask.setStatus(CheckTaskStatus.TO_BE_CHECK.getKey());
        checkTask.setSupplierId(purchaseOrder.getSupplierId());
        checkTask.setPurchaseOrderId(purchaseOrder.getId());
        checkTask.setCustomerOrderId(purchaseOrder.getCustomerOrderId());
        checkTask.setCustomerId(customerOrder.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.setPurchaseOrderItemId(purchaseOrderItem.getId());
            item.setProductId(purchaseOrderItem.getProductId());
            item.setProductName(productSpuDO.getName());
            item.setCategoryId(productSpuDO.getCategoryId());
            item.setCategoryName(productCategoryService.queryNameById(productSpuDO.getCategoryId()));
            item.setPicUrl(productSpuDO.getPicUrl());
            item.setIntroduction(productSpuDO.getIntroduction());
            item.setCheckCount(purchaseOrderItem.getCount());
            item.setUnitName(purchaseOrderItem.getProductUnit());
            item.setCheckResult(CheckTaskStatus.TO_BE_CHECK.getKey());
            item.setPurchaseAnnex(purchaseOrderItem.getAnnex());
            return item;
        }));

        return checkTask;
    }

}