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

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.WornOutboundItem;
import com.shzg.project.worn.mapper.WornOutboundItemMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.shzg.project.worn.mapper.WornOutboundBillMapper;
import com.shzg.project.worn.domain.WornOutboundBill;
import com.shzg.project.worn.service.IWornOutboundBillService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 出库单据Service业务层处理
 * 
 * @author shzg
 * @date 2026-04-08
 */
@Service
public class WornOutboundBillServiceImpl implements IWornOutboundBillService 
{
    @Autowired
    private WornOutboundBillMapper wornOutboundBillMapper;
    @Autowired
    private WornOutboundItemMapper wornOutboundItemMapper;
    @Autowired
    private WornUniqueCodeMapper wornUniqueCodeMapper;

    @Autowired
    private WornUniqueCodeEventMapper eventMapper;

    @Autowired
    private WornUniqueCodeMaterialMapper wornUniqueCodeMaterialMapper;
    /**
     * 查询出库单据
     * 
     * @param id 出库单据主键
     * @return 出库单据
     */
    @Override
    public WornOutboundBill selectWornOutboundBillById(Long id)
    {
        return wornOutboundBillMapper.selectWornOutboundBillById(id);
    }

    /**
     * 查询出库单据列表
     * 
     * @param wornOutboundBill 出库单据
     * @return 出库单据
     */
    @Override
    public List<WornOutboundBill> selectWornOutboundBillList(WornOutboundBill wornOutboundBill)
    {
        return wornOutboundBillMapper.selectWornOutboundBillList(wornOutboundBill);
    }

    /**
     * 新增出库单据
     * 
     * @param wornOutboundBill 出库单据
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertWornOutboundBill(WornOutboundBill wornOutboundBill){
        /* ================== 1. 参数校验 ================== */
        if (wornOutboundBill == null)
        {
            throw new RuntimeException("出库单参数不能为空");
        }
        if (wornOutboundBill.getItemList() == null || wornOutboundBill.getItemList().isEmpty())
        {
            throw new RuntimeException("出库明细不能为空");
        }

        /* ================== 2. 当前用户 ================== */
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        Long deptId = SecurityUtils.getLoginUser().getUser().getDeptId();

        wornOutboundBill.setProjectId(deptId);

        /* ================== 3. 主表赋值 ================== */
        wornOutboundBill.setCreateTime(DateUtils.getNowDate());
        wornOutboundBill.setCreateBy(String.valueOf(userId));
        wornOutboundBill.setBillType("0");
        wornOutboundBill.setStatus("0");
        wornOutboundBill.setIsDelete("0");

        if (wornOutboundBill.getBillNo() == null || "".equals(wornOutboundBill.getBillNo().trim()))
        {
            wornOutboundBill.setBillNo("DL" + System.currentTimeMillis());
        }

        /* ================== 4. 插入主表 ================== */
        int rows = wornOutboundBillMapper.insertWornOutboundBill(wornOutboundBill);
        if (rows <= 0)
        {
            throw new RuntimeException("出库单新增失败");
        }

        Long billId = wornOutboundBill.getId();
        String billNo = wornOutboundBill.getBillNo();

        if (billId == null)
        {
            throw new RuntimeException("出库单新增失败，ID未回填");
        }

        /* ================== 5. 插入明细 ================== */
        for (WornOutboundItem item : wornOutboundBill.getItemList())
        {
            if (item == null)
            {
                continue;
            }

            item.setBillId(billId);
            item.setBillNo(billNo);
            item.setCreateTime(DateUtils.getNowDate());
            item.setCreateBy(String.valueOf(userId));
            item.setIsDelete(item.getIsDelete());

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

            /* ================== 6. 唯一码联动 ================== */
            if (item.getUniqueCode() != null)
            {
                Integer code = item.getUniqueCode();

                Long uniqueId = wornUniqueCodeMapper.selectIdByCode(code);
                if (uniqueId == null)
                {
                    throw new RuntimeException("唯一码不存在：" + code);
                }

                WornUniqueCode unique = wornUniqueCodeMapper.selectByCode(code);

                // ❗必须是“已入库状态(2)”才能出库
                if (!"2".equals(unique.getStatus())){
                    throw new RuntimeException("唯一码[" + code + "]未入库，不能出库");
                }

                /* ===== 状态更新：2 → 3（出库申请） ===== */
                WornUniqueCode update = new WornUniqueCode();
                update.setCode(code);
                update.setStatus("3"); // ⭐已出库
                update.setUpdateBy(String.valueOf(userId));
                update.setUpdateTime(DateUtils.getNowDate());

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

                /* ================== 7. 插入事件 ================== */
                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(DateUtils.getNowDate());
                event.setIsDelete("0");

                int eventRows = eventMapper.insertWornUniqueCodeEvent(event);
                if (eventRows <= 0)
                {
                    throw new RuntimeException("唯一码事件记录失败：" + code);
                }
            }
        }

        return 1;
    }

    /**
     * 修改出库单据
     * 
     * @param wornOutboundBill 出库单据
     * @return 结果
     */
    @Override
    public int updateWornOutboundBill(WornOutboundBill wornOutboundBill)
    {
        wornOutboundBill.setUpdateTime(DateUtils.getNowDate());
        return wornOutboundBillMapper.updateWornOutboundBill(wornOutboundBill);
    }

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

    /**
     * 删除出库单据信息
     * 
     * @param id 出库单据主键
     * @return 结果
     */
    @Override
    public int deleteWornOutboundBillById(Long id)
    {
        return wornOutboundBillMapper.deleteWornOutboundBillById(id);
    }
    /**
     * 完成出库
     *
     * @param wornOutboundBill 出库单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int completeWornOutboundBill(WornOutboundBill wornOutboundBill)
    {
        /* ================== 1. 参数校验 ================== */
        if (wornOutboundBill == null)
        {
            throw new RuntimeException("出库单参数不能为空");
        }
        if (StringUtils.isEmpty(wornOutboundBill.getBillNo()))
        {
            throw new RuntimeException("出库单号不能为空");
        }

        /* ================== 2. 当前用户 ================== */
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        Date now = DateUtils.getNowDate();

        /* ================== 3. 查询出库单 ================== */
        WornOutboundBill dbBill = wornOutboundBillMapper.selectWornOutboundBillByBillNo(wornOutboundBill.getBillNo());
        if (dbBill == null)
        {
            throw new RuntimeException("出库单不存在：" + wornOutboundBill.getBillNo());
        }

        /* ================== 4. 查询出库明细 ================== */
        WornOutboundItem param = new WornOutboundItem();
        param.setBillNo(wornOutboundBill.getBillNo());

        List<WornOutboundItem> itemList = wornOutboundItemMapper.selectWornOutboundItemList(param);
        if (itemList == null || itemList.isEmpty())
        {
            throw new RuntimeException("出库明细不能为空");
        }

        /* ================== 5. 循环处理每个唯一码 ================== */
        for (WornOutboundItem item : itemList)
        {
            if (item == null){
                continue;
            }
            if ("1".equals(item.getIsDelete())){
                continue;
            }
            if (item.getUniqueCode() == null){
                throw new RuntimeException("出库明细存在空唯一码");
            }

            Integer code = item.getUniqueCode();

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

            /* ===== 5.2 只有状态3才能完成出库 ===== */
            if (!"3".equals(uniqueCode.getStatus())){
                if ("2".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 + "]当前状态不允许完成出库");
                }
            }

            /* ===== 5.3 更新唯一码状态：3 -> 4 ===== */
            WornUniqueCode update = new WornUniqueCode();
            update.setCode(code);
            update.setStatus("4");
            update.setUpdateBy(String.valueOf(userId));
            update.setUpdateTime(now);

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

            /* ===== 5.4 同步更新唯一码物料表：逻辑删除 ===== */
            WornUniqueCodeMaterial codeMaterial = new WornUniqueCodeMaterial();
            codeMaterial.setUniqueCodeId(uniqueCode.getId());
            codeMaterial.setIsDelete("1");
            codeMaterial.setUpdateBy(String.valueOf(userId));
            codeMaterial.setUpdateTime(now);

            int materialRows = wornUniqueCodeMaterialMapper.updateWornUniqueCodeMaterial(codeMaterial);
            if (materialRows <= 0){
                throw new RuntimeException("唯一码物料信息更新失败：" + code);
            }

            /* ===== 5.5 写事件记录 ===== */
            WornUniqueCodeEvent event = new WornUniqueCodeEvent();
            event.setUniqueCodeId(uniqueCode.getId());
            event.setEventType("4");
            event.setEventStatus("4");
            event.setEventDesc("完成出库，出库单号：" + dbBill.getBillNo());
            event.setOperatorId(userId);
            event.setOperatorName(SecurityUtils.getUsername());
            event.setCreateBy(String.valueOf(userId));
            event.setCreateTime(now);
            event.setIsDelete("0");

            int eventRows = eventMapper.insertWornUniqueCodeEvent(event);
            if (eventRows <= 0){
                throw new RuntimeException("唯一码事件记录失败：" + code);
            }
        }

        /* ================== 6. 更新出库单状态 ================== */
        WornOutboundBill updateBill = new WornOutboundBill();
        updateBill.setBillNo(dbBill.getBillNo());
        updateBill.setUpdateBy(String.valueOf(userId));
        updateBill.setUpdateTime(now);
        // 4. 判断该单据下是否全部明细都已出库
        int notOutboundCount = wornOutboundItemMapper.countNotOutboundByBillId(dbBill.getId());
        if (notOutboundCount == 0)
        {
            // 全部出库
            updateBill.setStatus("1");   // 已完成
            updateBill.setBillType("1"); //
        }
        else
        {
            // 部分出库
            updateBill.setStatus("2");   // 部分出库
            // billType 可不改
        }

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

        return 1;
    }
}
