package com.shzg.project.worn.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.shzg.common.utils.DateUtils;
import com.shzg.common.utils.SecurityUtils;
import com.shzg.common.utils.StringUtils;
import com.shzg.project.unique.domain.WornUniqueCode;
import com.shzg.project.unique.domain.WornUniqueCodeEvent;
import com.shzg.project.unique.domain.WornUniqueCodeMaterial;
import com.shzg.project.unique.mapper.WornUniqueCodeEventMapper;
import com.shzg.project.unique.mapper.WornUniqueCodeMapper;
import com.shzg.project.unique.mapper.WornUniqueCodeMaterialMapper;
import com.shzg.project.worn.domain.WornOutboundBill;
import com.shzg.project.worn.domain.WornTechnicalAppraisal;
import com.shzg.project.worn.domain.WornTechnicalAppraisalFile;
import com.shzg.project.worn.domain.dto.AppraisalFileDTO;
import com.shzg.project.worn.domain.dto.WornInboundItemDTO;
import com.shzg.project.worn.domain.dto.WornOutboundUpdateDTO;
import com.shzg.project.worn.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.shzg.project.worn.domain.WornOutboundItem;
import com.shzg.project.worn.service.IWornOutboundItemService;

/**
 * 出库单明细Service业务层处理
 * 
 * @author shzg
 * @date 2026-04-08
 */
@Service
public class WornOutboundItemServiceImpl implements IWornOutboundItemService 
{
    @Autowired
    private WornOutboundItemMapper wornOutboundItemMapper;
    @Autowired
    private WornUniqueCodeMapper wornUniqueCodeMapper;
    @Autowired
    private WornUniqueCodeEventMapper eventMapper;
    @Autowired
    private WornInboundBillMapper wornInboundBillMapper;
    @Autowired
    private WornUniqueCodeMaterialMapper wornUniqueCodeMaterialMapper;
    @Autowired
    private WornOutboundBillMapper wornOutboundBillMapper;
    @Autowired
    private WornTechnicalAppraisalMapper wornTechnicalAppraisalMapper;
    @Autowired
    private WornTechnicalAppraisalFileMapper wornTechnicalAppraisalFileMapper;
    /**
     * 查询出库单明细
     * 
     * @param id 出库单明细主键
     * @return 出库单明细
     */
    @Override
    public WornOutboundItem selectWornOutboundItemById(Long id)
    {
        return wornOutboundItemMapper.selectWornOutboundItemById(id);
    }

    /**
     * 查询出库单明细列表
     * 
     * @param wornOutboundItem 出库单明细
     * @return 出库单明细
     */
    @Override
    public List<WornOutboundItem> selectWornOutboundItemList(WornOutboundItem wornOutboundItem)
    {
        return wornOutboundItemMapper.selectWornOutboundItemList(wornOutboundItem);
    }

    /**
     * 新增出库单明细
     * 
     * @param wornOutboundItem 出库单明细
     * @return 结果
     */
    @Override
    public int insertWornOutboundItem(WornOutboundItem wornOutboundItem)
    {
        wornOutboundItem.setCreateTime(DateUtils.getNowDate());
        return wornOutboundItemMapper.insertWornOutboundItem(wornOutboundItem);
    }

    /**
     * 修改出库单明细
     *
     * @param dto 出库单明细
     * @return 结果
     */
    @Override
    public int updateWornOutboundItem(WornOutboundUpdateDTO dto)
    {
        if (dto == null){
            throw new RuntimeException("出库单参数不能为空");
        }

        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        Date now = DateUtils.getNowDate();

        // 1. 更新主表
        WornOutboundBill bill = new WornOutboundBill();
        bill.setBillNo(dto.getBillNo());
        bill.setWarehouseCode(dto.getWarehouseCode());
        bill.setWarehouseName(dto.getWarehouseName());
        bill.setAreaCode(dto.getAreaCode());
        bill.setAreaName(dto.getAreaName());
        bill.setRemark(dto.getBillRemark());
        bill.setOutboundTime(dto.getOutboundTime());
        bill.setStatus("0");
        bill.setUpdateBy(String.valueOf(userId));
        bill.setUpdateTime(now);

        int billRows = wornOutboundBillMapper.updateWornOutboundBill(bill);
        if (billRows <= 0){
            throw new RuntimeException("出库单更新失败");
        }

        WornOutboundBill billUp = wornOutboundBillMapper.selectWornOutboundBillByBillNo(dto.getBillNo());
        if (billUp == null){
            throw new RuntimeException("出库单不存在：" + dto.getBillNo());
        }

        // 2. 更新 / 新增 / 删除明细
        if (dto.getItemList() != null && !dto.getItemList().isEmpty()){
            for (WornInboundItemDTO itemDTO : dto.getItemList()){
                if (itemDTO == null){
                    continue;
                }

                // 删除
                if ("1".equals(itemDTO.getIsDelete())){
                    if (itemDTO.getId() != null){
                        WornOutboundItem oldItem = wornOutboundItemMapper.selectWornOutboundItemById(itemDTO.getId());
                        if (oldItem != null){
                            oldItem.setIsDelete("1");
                            oldItem.setUpdateBy(String.valueOf(userId));
                            oldItem.setUpdateTime(now);

                            int deleteRows = wornOutboundItemMapper.updateWornOutboundItem(oldItem);
                            if (deleteRows <= 0){
                                throw new RuntimeException("出库明细删除失败");
                            }

                            if (oldItem.getUniqueCode() != null){
                                rollbackUniqueCodeOut(userId, oldItem.getUniqueCode(), now);
                            }
                        }
                    }
                    continue;
                }

                // 新增
                if (itemDTO.getId() == null){
                    WornOutboundItem newItem = new WornOutboundItem();
                    newItem.setBillId(billUp.getId());
                    newItem.setBillNo(dto.getBillNo());
                    newItem.setMaterialId(itemDTO.getMaterialId());
                    newItem.setQuantity(itemDTO.getQuantity());
                    newItem.setRemark(itemDTO.getRemark());
                    newItem.setUniqueCode(itemDTO.getUniqueCode());
                    newItem.setIsDelete("0");
                    newItem.setCreateBy(String.valueOf(userId));
                    newItem.setCreateTime(now);

                    int itemRows = wornOutboundItemMapper.insertWornOutboundItem(newItem);
                    if (itemRows <= 0){
                        throw new RuntimeException("出库明细新增失败");
                    }

                    if (newItem.getUniqueCode() != null){
                        handleUniqueCodeOut(userId, dto.getBillNo(), newItem.getUniqueCode(), now);
                    }
                }else{
                    // 更新
                    WornOutboundItem oldItem = wornOutboundItemMapper.selectWornOutboundItemById(itemDTO.getId());
                    if (oldItem == null)
                    {
                        throw new RuntimeException("出库明细不存在，ID：" + itemDTO.getId());
                    }

                    Integer oldCode = oldItem.getUniqueCode();
                    Integer newCode = itemDTO.getUniqueCode();

                    oldItem.setMaterialId(itemDTO.getMaterialId());
                    oldItem.setQuantity(itemDTO.getQuantity());
                    oldItem.setRemark(itemDTO.getRemark());
                    oldItem.setUniqueCode(newCode);
                    oldItem.setUpdateBy(String.valueOf(userId));
                    oldItem.setUpdateTime(now);

                    int itemRows = wornOutboundItemMapper.updateWornOutboundItem(oldItem);
                    if (itemRows <= 0)
                    {
                        throw new RuntimeException("出库明细更新失败");
                    }

                    // 唯一码物料表更改（如果你出库也维护这个表，就保留；如果不维护可删掉）
                    WornUniqueCode wornUniqueCode = new WornUniqueCode();
                    wornUniqueCode.setCode(oldCode);
                    List<WornUniqueCode> list = wornUniqueCodeMapper.selectWornUniqueCodeList(wornUniqueCode);
                    if (list != null && list.size() > 0){
                        Long uniqueCodeId = list.get(0).getId();
                        WornUniqueCodeMaterial wornUniqueCodeMaterial = new WornUniqueCodeMaterial();
                        wornUniqueCodeMaterial.setUniqueCodeId(uniqueCodeId);
                        wornUniqueCodeMaterial.setQuantity(itemDTO.getQuantity());
                        wornUniqueCodeMaterial.setRemark(itemDTO.getRemark());
                        wornUniqueCodeMaterialMapper.updateWornUniqueCodeMaterial(wornUniqueCodeMaterial);
                    }

                    // 唯一码变更处理
                    if (oldCode != null && !oldCode.equals(newCode)){
                        rollbackUniqueCodeOut(userId, oldCode, now);
                    }
                    if (newCode != null && !newCode.equals(oldCode)){
                        handleUniqueCodeOut(userId, dto.getBillNo(), newCode, now);
                    }
                }
            }
        }

        return 1;
    }

    /**
     * 批量删除出库单明细
     * 
     * @param ids 需要删除的出库单明细主键
     * @return 结果
     */
    @Override
    public int deleteWornOutboundItemByIds(Long[] ids)
    {
        return wornOutboundItemMapper.deleteWornOutboundItemByIds(ids);
    }

    /**
     * 删除出库单明细信息
     * 
     * @param id 出库单明细主键
     * @return 结果
     */
    @Override
    public int deleteWornOutboundItemById(Long id)
    {
        return wornOutboundItemMapper.deleteWornOutboundItemById(id);
    }
    /**
     * 查询出库单明细列表
     *
     * @param wornOutboundItem 出库单明细
     * @return 出库单明细
     */
    /**
     * 查询出库单明细列表
     *
     * @param wornOutboundItem 出库单明细
     * @return 出库单明细
     */
    @Override
    public WornOutboundUpdateDTO selectWornOutboundItemByBillNo(WornOutboundItem wornOutboundItem)
    {
        String billNo = wornOutboundItem.getBillNo();
        if (billNo == null || "".equals(billNo.trim()))
        {
            return null;
        }

        // 1. 查询出库单明细列表
        WornOutboundItem param = new WornOutboundItem();
        param.setBillNo(billNo);

        List<WornOutboundItem> itemList = wornOutboundItemMapper.selectWornOutboundItemList(param);

        if (itemList == null || itemList.isEmpty())
        {
            return null;
        }

        // 2. 取第一条作为主数据
        WornOutboundItem first = itemList.get(0);

        // 3. 组装主表 DTO
        WornOutboundUpdateDTO dto = new WornOutboundUpdateDTO();
        dto.setBillId(first.getBillId());
        dto.setBillNo(first.getBillNo());
        dto.setBillType(first.getBillType());
        dto.setWarehouseCode(first.getWarehouseCode());
        dto.setWarehouseName(first.getWarehouseName());
        dto.setAreaCode(first.getAreaCode());
        dto.setAreaName(first.getAreaName());
        dto.setBillRemark(first.getBillRemark());
        dto.setOutboundTime(first.getOutboundTime());
        dto.setStatus(first.getBillStatus());
        dto.setCreateTime(first.getCreateTime());

        List<WornInboundItemDTO> dtoList = new ArrayList<>();

        // 4. 组装明细
        for (WornOutboundItem item : itemList)
        {
            WornInboundItemDTO itemDTO = new WornInboundItemDTO();

            itemDTO.setId(item.getId());
            itemDTO.setMaterialId(item.getMaterialId());
            itemDTO.setMaterialName(item.getMaterialName());
            itemDTO.setMaterialCode(item.getMaterialCode());
            itemDTO.setMaterialShortName(item.getMaterialShortName());
            itemDTO.setModel(item.getModel());
            itemDTO.setSpecification(item.getSpecification());
            itemDTO.setTypeName(item.getTypeName());
            itemDTO.setQuantity(item.getQuantity());
            itemDTO.setRemark(item.getRemark());
            itemDTO.setUniqueCode(item.getUniqueCode());
            itemDTO.setIsDelete(StringUtils.isEmpty(item.getIsDelete()) ? "0" : item.getIsDelete());
            itemDTO.setTypeParentNames(item.getTypeParentNames());
            itemDTO.setUnitId(item.getUnitId());
            itemDTO.setUnitName(item.getUnitName());
            itemDTO.setStatus(item.getStatus());

            dtoList.add(itemDTO);
        }

        dto.setItemList(dtoList);

        // 5. 查询技术鉴定表信息
        WornTechnicalAppraisal appraisalQuery = new WornTechnicalAppraisal();
        appraisalQuery.setBillNo(billNo);

        List<WornTechnicalAppraisal> appraisalList =
                wornTechnicalAppraisalMapper.selectWornTechnicalAppraisalList(appraisalQuery);

        if (appraisalList != null && !appraisalList.isEmpty())
        {
            WornTechnicalAppraisal appraisal = appraisalList.get(0);

            dto.setAppraisalId(appraisal.getId());
            dto.setAppraisalNo(appraisal.getAppraisalNo());
            dto.setAppraisalDesc(appraisal.getAppraisalDesc());
            dto.setAppraisalRemark(appraisal.getRemark());
            dto.setAppraisalTime(appraisal.getCreateTime());
            // 查询鉴定表附件
            List<WornTechnicalAppraisalFile> fileList =
                    wornTechnicalAppraisalFileMapper.selectWornTechnicalAppraisalFileByAppraisalId(appraisal.getId());

            List<AppraisalFileDTO> appraisalFileList = new ArrayList<>();

            if (fileList != null && !fileList.isEmpty())
            {
                for (WornTechnicalAppraisalFile file : fileList)
                {
                    if (file == null)
                    {
                        continue;
                    }

                    AppraisalFileDTO fileDTO = new AppraisalFileDTO();
                    fileDTO.setName(file.getFileName());
                    fileDTO.setUrl(file.getFileUrl());

                    appraisalFileList.add(fileDTO);
                }
            }

            dto.setAppraisalFileList(appraisalFileList);
        }

        return dto;
    }

    /**
     * 出库明细删除/替换时，唯一码状态回滚：3 -> 2
     */
    private void rollbackUniqueCodeOut(Long userId, Integer code, Date now)
    {
        if (code == null){
            return;
        }

        WornUniqueCode uniqueCode = wornUniqueCodeMapper.selectByCode(code);
        if (uniqueCode == null){
            throw new RuntimeException("唯一码不存在：" + code);
        }

        // 只有“生成出库单号”状态才回滚
        if (!"3".equals(uniqueCode.getStatus())){
            return;
        }

        WornUniqueCode update = new WornUniqueCode();
        update.setCode(code);
        update.setBillNo(null);
        update.setStatus("2");
        update.setUpdateBy(String.valueOf(userId));
        update.setUpdateTime(now);

        int updateRows = wornUniqueCodeMapper.updateByCode(update);
        if (updateRows <= 0)
        {
            throw new RuntimeException("唯一码状态回滚失败：" + code);
        }

        Long uniqueId = wornUniqueCodeMapper.selectIdByCode(code);
        if (uniqueId != null){
            WornUniqueCodeEvent event = new WornUniqueCodeEvent();
            event.setUniqueCodeId(uniqueId);
            event.setEventType("2");
            event.setEventStatus("2");
            event.setEventDesc("出库单编辑回滚，恢复已入库状态");
            event.setOperatorId(userId);
            event.setOperatorName(SecurityUtils.getUsername());
            event.setCreateBy(String.valueOf(userId));
            event.setCreateTime(now);
            event.setIsDelete("0");

            eventMapper.insertWornUniqueCodeEvent(event);
        }
    }
    /**
     * 出库申请时，唯一码状态处理：2 -> 3
     */
    private void handleUniqueCodeOut(Long userId, String billNo, Integer code, Date now)
    {
        if (code == null){
            return;
        }

        WornUniqueCode uniqueCode = wornUniqueCodeMapper.selectByCode(code);
        if (uniqueCode == null)
        {
            throw new RuntimeException("唯一码不存在：" + code);
        }

        if (!"2".equals(uniqueCode.getStatus())) {
            if ("3".equals(uniqueCode.getStatus()))
            {
                throw new RuntimeException("唯一码已生成出库单号，请勿重复操作：" + code);
            }else if ("4".equals(uniqueCode.getStatus())){
                throw new RuntimeException("唯一码已完成出库：" + code);
            }else if ("9".equals(uniqueCode.getStatus())){
                throw new RuntimeException("唯一码已作废：" + code);
            }else{
                throw new RuntimeException("唯一码状态不允许出库：" + code);
            }
        }

        WornUniqueCode update = new WornUniqueCode();
        update.setCode(code);
        update.setBillNo(billNo);
        update.setStatus("3");
        update.setUpdateBy(String.valueOf(userId));
        update.setUpdateTime(now);

        int updateRows = wornUniqueCodeMapper.updateByCode(update);
        if (updateRows <= 0)
        {
            throw new RuntimeException("唯一码状态更新失败：" + code);
        }

        Long uniqueId = wornUniqueCodeMapper.selectIdByCode(code);
        if (uniqueId != null)
        {
            WornUniqueCodeEvent event = new WornUniqueCodeEvent();
            event.setUniqueCodeId(uniqueId);
            event.setEventType("3");
            event.setEventStatus("3");
            event.setEventDesc("编辑出库单，生成出库单号：" + billNo);
            event.setOperatorId(userId);
            event.setOperatorName(SecurityUtils.getUsername());
            event.setCreateBy(String.valueOf(userId));
            event.setCreateTime(now);
            event.setIsDelete("0");

            eventMapper.insertWornUniqueCodeEvent(event);
        }
    }
}
