package com.ruoyi.inventory.service.impl;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.inventory.domain.vo.InboundMaterialTotalVO;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.inventory.domain.vo.InboundTemplateVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.inventory.domain.InboundOrderItems;
import com.ruoyi.inventory.mapper.InboundOrdersMapper;
import com.ruoyi.inventory.domain.InboundOrders;
import com.ruoyi.inventory.service.IInboundOrdersService;

/**
 * 入库单主Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-12-02
 */
@Service
public class InboundOrdersServiceImpl implements IInboundOrdersService 
{
    @Autowired
    private InboundOrdersMapper inboundOrdersMapper;
    private static final Logger log = LoggerFactory.getLogger(InboundOrdersServiceImpl.class);
    /**
     * 查询入库单主
     * 
     * @param id 入库单主主键
     * @return 入库单主
     */
    @Override
    public InboundOrders selectInboundOrdersById(String id)
    {
        return inboundOrdersMapper.selectInboundOrdersById(id);
    }

    /**
     * 查询入库单主列表
     * 
     * @param inboundOrders 入库单主
     * @return 入库单主
     */
    @Override
    public List<InboundOrders> selectInboundOrdersList(InboundOrders inboundOrders)
    {
        return inboundOrdersMapper.selectInboundOrdersList(inboundOrders);
    }

    /**
     * 新增入库单主
     * 
     * @param inboundOrders 入库单主
     * @return 结果
     */
    @Transactional
    @Override
    public int insertInboundOrders(InboundOrders inboundOrders)
    {
        inboundOrders.setCreateTime(DateUtils.getNowDate());
        int rows = inboundOrdersMapper.insertInboundOrders(inboundOrders);
        insertInboundOrderItems(inboundOrders);
        return rows;
    }

    /**
     * 修改入库单主
     * 
     * @param inboundOrders 入库单主
     * @return 结果
     */
    @Transactional
    @Override
    public int updateInboundOrders(InboundOrders inboundOrders)
    {
        inboundOrders.setUpdateTime(DateUtils.getNowDate());
        inboundOrdersMapper.deleteInboundOrderItemsByOrderId(inboundOrders.getOrderId());
        insertInboundOrderItems(inboundOrders);
        return inboundOrdersMapper.updateInboundOrders(inboundOrders);
    }

    /**
     * 批量删除入库单主
     * 
     * @param ids 需要删除的入库单主主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteInboundOrdersByIds(String[] ids)
    {
        inboundOrdersMapper.deleteInboundOrderItemsByOrderIds(ids);
        return inboundOrdersMapper.deleteInboundOrdersByIds(ids);
    }

    /**
     * 删除入库单主信息
     * 
     * @param id 入库单主主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteInboundOrdersById(String id)
    {
        inboundOrdersMapper.deleteInboundOrderItemsByOrderId(id);
        return inboundOrdersMapper.deleteInboundOrdersById(id);
    }

    /**
     * 新增入库单明细信息
     * 
     * @param inboundOrders 入库单主对象
     */
    public void insertInboundOrderItems(InboundOrders inboundOrders)
    {
        List<InboundOrderItems> inboundOrderItemsList = inboundOrders.getInboundOrderItemsList();
        String orderId = inboundOrders.getOrderId();
        if (StringUtils.isNotNull(inboundOrderItemsList))
        {
            List<InboundOrderItems> list = new ArrayList<InboundOrderItems>();
            for (InboundOrderItems inboundOrderItems : inboundOrderItemsList)
            {
                inboundOrderItems.setId(UUID.randomUUID().toString());
                inboundOrderItems.setOrderId(orderId);
                inboundOrderItems.setCreateTime(DateUtils.getNowDate());
                inboundOrderItems.setInboundOrderId(inboundOrders.getId());
                list.add(inboundOrderItems);
            }
            if (list.size() > 0)
            {
                inboundOrdersMapper.batchInboundOrderItems(list);
            }
        }
    }

    /**
     * 导入入库单明细信息
     *
     * @param  inboundOrdersList,isUpdateSupport,operName 入库单数据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importInboundOrders(List<InboundTemplateVO> inboundOrdersList, Boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(inboundOrdersList) || inboundOrdersList.size() == 0) {
            throw new ServiceException("导入数据不能为空！");
        }
        // 2. 初始化统计变量
        int totalMainSuccess = 0; // 成功的主表数量
        int totalMainFailure = 0; // 失败的主表数量
        int totalItemSuccess = 0; // 成功的明细数量
        int totalItemFailure = 0; // 失败的明细数量
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        Date now = DateUtils.getNowDate();
        Long userId = SecurityUtils.getUserId();
        String operId = userId.toString();

        // 3. 按入库单号分组（核心：同一入库单的多条明细归为一组）
        Map<String, List<InboundTemplateVO>> orderGroupMap = inboundOrdersList.stream()
                .filter(vo -> StringUtils.isNotBlank(vo.getOrderId())) // 过滤无入库单号的无效行
                .collect(Collectors.groupingBy(InboundTemplateVO::getOrderId));

        // 4. 遍历每个入库单分组处理
        for (Map.Entry<String, List<InboundTemplateVO>> entry : orderGroupMap.entrySet()) {
            String orderId = entry.getKey();
            List<InboundTemplateVO> voList = entry.getValue();
            InboundOrders mainDO = null;
            List<InboundOrderItems> itemDOList = new ArrayList<>();

            try {
                // 4.1 处理主表（每个入库单号只处理一次主表）
                InboundTemplateVO firstVO = voList.get(0); // 取第一条VO的主表信息
                // 检查入库单是否已存在
                InboundOrders existMain = inboundOrdersMapper.selectInboundOrdersByOrderId(orderId);
                if (existMain != null) {
                    if (!isUpdateSupport) {
                        // 不支持更新，跳过该入库单
                        totalMainFailure++;
                        failureMsg.append(String.format("入库单号【%s】已存在，且不支持更新，跳过导入；\n", orderId));
                        totalItemFailure += voList.size(); // 该单的明细全部失败
                        continue;
                    }
                    // 支持更新，复用已有主表ID
                    mainDO = existMain;
                    // 复制VO中的主表字段到已有主表（只更新可修改的字段）
                    BeanUtils.copyProperties(firstVO, mainDO, "id", "createBy", "createTime"); // 排除不可更新字段
                    mainDO.setUpdateBy(operId);
                    mainDO.setUpdateTime(now);
                    mainDO.setUpdateUserCode(operId);
                    // 更新主表
                    inboundOrdersMapper.updateInboundOrders(mainDO);
                    totalMainSuccess++;
                    successMsg.append(String.format("入库单号【%s】已更新；\n", orderId));
                } else {
                    // 新增主表
                    mainDO = new InboundOrders();
                    // 复制主表字段（只复制主表相关字段，避免物料字段污染）
                    BeanUtils.copyProperties(firstVO, mainDO,
                            "sapNo", "materialName", "plannedQuantity", "actualQuantity",
                            "plannedPackages", "materialUnit", "materialRemark"); // 排除子表字段
                    // 填充主表必填字段
                    mainDO.setId(UUID.randomUUID().toString());
                    mainDO.setOrderId(orderId);
                    mainDO.setCreateBy(operId);
                    mainDO.setCreateTime(now);
                    mainDO.setCreateUserCode(operId);
                    mainDO.setUpdateBy(operId);
                    mainDO.setUpdateTime(now);
                    mainDO.setUpdateUserCode(operId);
                    // 设置默认值
                    if (mainDO.getSortNo() == null) {
                        mainDO.setSortNo(0L);
                    }
                    if (mainDO.getOrderStatus() == null) {
                        mainDO.setOrderStatus(1L); // 默认草稿状态
                    }
                    // 插入主表
                    inboundOrdersMapper.insertInboundOrders(mainDO);
                    totalMainSuccess++;
                    successMsg.append(String.format("入库单号【%s】已新增；\n", orderId));
                }

                // 4.2 处理子表明细（每条VO对应一条明细）
                for (InboundTemplateVO vo : voList) {
                    InboundOrderItems itemDO = new InboundOrderItems();
                    // 复制子表字段（物料相关）
                    BeanUtils.copyProperties(vo, itemDO,
                            "orderId", "systemNo", "orderTypeId", "batchId"); // 排除主表字段
                    // 填充明细必填字段
                    itemDO.setId(UUID.randomUUID().toString());
                    itemDO.setMaterialId(vo.getSapNo());
                    itemDO.setOrderId(orderId); // 关联入库单号
                    itemDO.setBatchId(mainDO.getBatchId());
                    itemDO.setInboundOrderId(mainDO.getId()); // 关联主表ID（核心！）
                    itemDO.setCreateBy(operId);
                    itemDO.setCreateTime(now);
                    itemDO.setCreateUserCode(operId);
                    itemDO.setSortNo(0L);
                    // 校验物料字段（示例：必填sapNo）
                    if (StringUtils.isBlank(vo.getSapNo())) {
                        throw new ServiceException(String.format("入库单号【%s】的物料SAP号为空，明细导入失败", orderId));
                    }
                    System.out.println(itemDO);
                    itemDOList.add(itemDO);
                }

                // 4.3 批量插入明细
                if (!CollectionUtils.isEmpty(itemDOList)) {
                    int itemSuccess = inboundOrdersMapper.batchInboundOrderItems(itemDOList);
                    totalItemSuccess += itemSuccess;
                    totalItemFailure += (itemDOList.size() - itemSuccess);
                    successMsg.append(String.format("入库单号【%s】成功导入%d条物料明细；\n", orderId, itemSuccess));
                    if (itemDOList.size() - itemSuccess > 0) {
                        failureMsg.append(String.format("入库单号【%s】有%d条物料明细导入失败；\n", orderId, itemDOList.size() - itemSuccess));
                    }
                }

            } catch (Exception e) {
                // 单个入库单处理失败，统计错误
                totalMainFailure++;
                totalItemFailure += voList.size();
                failureMsg.append(String.format("入库单号【%s】处理失败：%s；\n", orderId, e.getMessage()));
                // 打印异常栈，方便调试
                log.error("导入入库单【{}】失败", orderId, e);
            }
        }

        // 5. 结果汇总
        if (totalMainFailure > 0 || totalItemFailure > 0) {
            // 有失败数据，抛出异常提示
            String finalFailureMsg = String.format(
                    "导入结果：成功新增/更新%d个入库单，失败%d个；成功导入%d条明细，失败%d条。失败详情：%s",
                    totalMainSuccess, totalMainFailure, totalItemSuccess, totalItemFailure, failureMsg.toString()
            );
            throw new ServiceException(finalFailureMsg);
        } else {
            // 全部成功
            String finalSuccessMsg = String.format(
                    "恭喜您，数据已全部导入成功！共处理%d个入库单，成功导入%d条物料明细。详情：%s",
                    totalMainSuccess, totalItemSuccess, successMsg.toString()
            );
            return finalSuccessMsg;
        }
    }
    /**
     * 统计本月入库数量
     *
     * @return 结果
     */
    @Override
    public int countInboundOrders() {
        String monthParam = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
        return inboundOrdersMapper.countInboundOrders(monthParam);
    }
    /**
     * 按数量统计本月入库物料Top前10
     * @return 结果
     */
    @Override
    public List<InboundMaterialTotalVO> countInboundMaterialQuantity() {
        String monthParam = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
        return inboundOrdersMapper.countInboundMaterialQuantity(monthParam);
    }
    /**
     * 按金额统计本月入库物料Top前10
     * @return 结果
     */
    @Override
    public List<InboundMaterialTotalVO> countInboundMaterialMoney() {
        String monthParam = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
        return inboundOrdersMapper.countInboundMaterialMoney(monthParam);
    }
}
