package com.scpyun.platform.jilinsscgsdp.service.impl;

import com.scpyun.base.bean.Page;
import com.scpyun.base.core.annotation.Api;
import com.scpyun.base.core.annotation.ApiOperation;
import com.scpyun.base.core.exception.CustomException;
import com.scpyun.base.db.service.CommonService;
import com.scpyun.base.utils.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api("办公用品领用管理")
@Service("keyDmBorrow")
public class KeyDmBorrowServiceImpl {
    @Autowired
    private CommonService commonService;

    private static final String SUCCESS = "success";
    private final String namespace = "com.scpyun.platform.standard.jilinsscgsdp.keyDmBorrow.";
    private final String detailNamespace = "com.scpyun.platform.standard.jilinsscgsdp.keyDmBorrowDetail.";
    private final String materialNamespace = "com.scpyun.platform.standard.jilinsscgsdp.keyDmMaterialLog.";
    private final String userNamespace = "com.scpyun.platform.standard.jilinsscgsdp.keyDmUser.";
    private Map<String, String> userMap;
    //    把用户的id和名做成字典
    @PostConstruct
    public void initUserMap() {
        List<Map<String,Object>> userList = commonService.findList(userNamespace + "getUserMap", null);
        // 此时commonService已被注入，非null
        userMap = new HashMap<>();
        for (Map<String, Object> user : userList) {
            String userId = String.valueOf(user.get("Id")); // 转为String，避免类型问题
            String userName = (String) user.get("name");
            if (userId != null && userName != null) { // 空值防御
                userMap.put(userId, userName);
            }
        }
    }
    @ApiOperation(value = "领用申请列表", desc = "分页查询")
    public Page<Map<String, Object>> selectList(Map<String, Object> map) {
        if (map == null) map = new HashMap<>();
        Map<String, Object> user = (Map<String, Object>) map.get("_user");
        map.put("user", user);
        return commonService.findPage(namespace + "selectList", map);
    }

    @ApiOperation(value = "待审核列表", desc = "分页查询待审核")
    public Page<Map<String, Object>> selectPendingList(Map<String, Object> map) {
        if (map == null) map = new HashMap<>();
        Map<String, Object> user = (Map<String, Object>) map.get("_user");
        map.put("params", user);
        return commonService.findPage(namespace + "selectPendingList", map);
    }

    @ApiOperation(value = "历史申请列表", desc = "分页查询历史申请")
    public Page<Map<String, Object>> selectHistoryList(Map<String, Object> map) {
        if (map == null) map = new HashMap<>();
        return commonService.findPage(namespace + "selectHistoryList", map);
    }

    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "保存申请（含明细）", desc = "新增或修改申请")
    public String save(Map<String, Object> map) {
        if (map == null) throw new CustomException("参数不能为空");
        Object id = map.get("id");
        List<Map<String, Object>> details = (List<Map<String, Object>>) map.get("details");
        Map<String, Object> user = (Map<String, Object>) map.get("_user");
        //日期格式转换
        // 日期格式转换：兼容 2025-12-26 和 2025-12-25T16:00:00.000Z 两种格式
        String dateStr = (String) map.get("expected_return_date");
        Date expected_return_date = null;
        if (dateStr != null && !dateStr.trim().isEmpty()) {
            try {
                if (dateStr.contains("T") || dateStr.contains("Z")) {
                    // 处理带时区的ISO格式：转换为东八区日期
                    DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_INSTANT;
                    Instant instant = Instant.parse(dateStr);
                    // 转换为东八区的LocalDate
                    LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
                    expected_return_date = java.sql.Date.valueOf(localDate);
                } else {
                    // 处理纯日期格式（2025-12-26）
                    LocalDate localDate = LocalDate.parse(dateStr);
                    expected_return_date = java.sql.Date.valueOf(localDate);
                }
            } catch (DateTimeParseException e) {
                throw new CustomException("日期格式错误，支持格式：2025-12-26 或 2025-12-26T16:00:00.000Z");
            }
        }
        initUserMap();
        map.put("approver_name",userMap.get(map.get("approver_id")));
        map.put("expected_return_date", expected_return_date);
        if (id == null || String.valueOf(id).trim().isEmpty()) {
            map.put("id", UUID.randomUUID().toString());
            map.put("applicant_id",user.get("id"));
            map.put("applicant_name", user.get("name"));
            map.put("department_id", user.get("company_id"));
            map.put("department_name", user.get("company_name"));


            map.put("approval_status", 0);
            map.put("issue_status", 0);
            map.put("order_no", 0);
            // insert application
            if (commonService.insert(namespace + "insert", map) != 1) throw new CustomException("保存失败");
            // insert details if any
            if (details != null) {
                for (Map<String, Object> d : details) {
                    d.put("application_id", map.get("id"));
                    commonService.insert( detailNamespace + "insertDetail", d);
                }
            }
        } else {
            int aff = commonService.update(namespace + "update", map);
            if (aff < 0) throw new CustomException("保存失败");
            // for simplicity, delete old details and insert new
            commonService.delete(namespace + "deleteDetailsByApplicationId", map);
            if (details != null) {
                for (Map<String, Object> d : details) {
                    d.put("application_id", map.get("id"));
                    commonService.insert(detailNamespace + "insertDetail", d);
                }
            }
        }
        return SUCCESS;
    }

    @ApiOperation(value = "提交申请", desc = "提交进入审批")
    public String submit(Map<String, Object> map) {
        if (map == null || map.get("id") == null) throw new CustomException("参数缺失");
        int aff = commonService.update(namespace + "submit", map);
        if (aff < 0) throw new CustomException("提交失败");
        return SUCCESS;
    }

    @ApiOperation(value = "撤回申请", desc = "撤回审核中申请")
    public String revoke(Map<String, Object> map) {
        if (map == null || map.get("id") == null) throw new CustomException("参数缺失");
        int aff = commonService.update(namespace + "revoke", map);
        if (aff < 0) throw new CustomException("撤回失败");
        return SUCCESS;
    }


    // 开启事务，发生异常时全量回滚
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "审批通过", desc = "审批通过并生成出库，更新库存与日志")
    public String approve(Map<String, Object> map) {
        // 1. 严格参数校验
        if (map == null || map.get("id") == null || map.get("id").toString().trim().isEmpty()) {
            throw new CustomException("参数缺失：申请ID不能为空");
        }

        // 2. 更新审批状态为通过
        int aff = commonService.update(namespace + "approve", map);
        // 受影响行数为0代表未找到对应申请，判定为审批失败
        if (aff == 0) {
            throw new CustomException("审批失败：未找到ID为" + map.get("id") + "的申请记录");
        }

        // 3. 生成出库记录
        commonService.insert(namespace + "insertOutboundByApplication", map);
        commonService.insert(namespace + "insertOutboundDetail", map);
        // 4. 获取申领明细
        Map<String, Object> detailItemsMap = getById(map);
        List<Map<String, Object>> detailsList = (List<Map<String, Object>>) detailItemsMap.get("details");
        // 校验明细列表非空
        if (detailsList == null || detailsList.isEmpty()) {
            throw new CustomException("审批失败：该申请无物料申领明细");
        }

        StringBuffer sb = new StringBuffer();
        // 遍历处理每个物料
        for (Map<String, Object> details : detailsList) {
            if (details == null || details.get("material_id") == null) {
                sb.append("物料明细为空，已跳过处理；");
                continue;
            }

            // 5. 查询物料库存信息
            Map<String, Object> inventoryMap = commonService.getObject(namespace + "selectInventoryByMaterialId", details);
            if (inventoryMap == null) {
                String materialName = (String) details.get("material_name");
                sb.append((materialName == null ? "未知物料" : materialName) + "无库存信息，已跳过申领；");
                continue;
            }

            // 6. 空值处理：获取库存相关字段，默认值为0
            int totalQuantity = getIntValue(inventoryMap, "total_quantity");
            int borrowedQuantity = getIntValue(inventoryMap, "borrowed_quantity");
            int damagedQuantity = getIntValue(inventoryMap, "damaged_quantity");
            int borrowQuantity = getIntValue(details, "apply_quantity");
            String materialName = (String) details.get("material_name");
            materialName = materialName == null ? "未知物料" : materialName;

            // 7. 判断是否为消耗品（can_borrow=0 为消耗品，其他为非消耗品）
            int canBorrow = getIntValue(inventoryMap, "can_borrow");
            int remainQuantity; // 剩余可申领数量
            String updateSqlId;  // 库存更新的SQL ID

            if (canBorrow == 0) {
                // 消耗品：总库存 - 本次申领数量
                remainQuantity = totalQuantity - borrowQuantity;
                updateSqlId = namespace + "updateInventoryTotalQuantity";
            } else {
                // 非消耗品：总库存 - 已借 - 损坏 - 本次申领
                remainQuantity = totalQuantity - borrowedQuantity - damagedQuantity - borrowQuantity;
                updateSqlId = namespace + "updateInventoryBorrowedQuantity";
            }

            // 8. 库存校验与扣减
            if (remainQuantity > 0 && borrowQuantity > 0) {
                int row = commonService.update(updateSqlId, details);
                if (row > 0) {
                    sb.append(materialName + "申领成功，库存已扣减；");
                } else {
                    sb.append(materialName + "申领失败：库存扣减操作未生效；");
                }
            } else {
                sb.append(materialName + "该物料库存不足（剩余可申领：" + remainQuantity + "），已跳过申领；");
            }
        }
        // 插入日志：传当前物料的明细，而非整个申请的明细
        detailItemsMap.put("op_type", 2);
        commonService.insert(materialNamespace + "insertLog", detailItemsMap);
        return sb.toString();
    }

    // 工具方法：安全获取Map中的int值，避免空指针和类型转换异常
    private int getIntValue(Map<String, Object> map, String key) {
        if (map == null || map.get(key) == null) {
            return 0;
        }
        Object value = map.get(key);
        if (value instanceof Integer) {
            return (Integer) value;
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    @ApiOperation(value = "审批驳回", desc = "审批驳回，需保存意见")
    public String reject(Map<String, Object> map) {
        if (map == null || map.get("id") == null) throw new CustomException("参数缺失");
        int aff = commonService.update(namespace + "reject", map);
        if (aff < 0) throw new CustomException("驳回失败");
        return SUCCESS;
    }

    @ApiOperation(value = "根据ID查询申请及明细/日志", desc = "详情")
    public Map<String, Object> getById(Map<String, Object> map) {
        if (map == null || map.get("id") == null) throw new CustomException("参数缺失");
        Map<String, Object> ret = new HashMap<>();
        Map<String, Object> app = commonService.getObject(namespace + "getById", map);
        ret.putAll(app == null ? new HashMap<>() : app);
        List<Map<String, Object>> details = commonService.findList(detailNamespace + "selectDetailsByApplicationId", map);
        ret.put("details", details == null ? new java.util.ArrayList<>() : details);
        // logs from material log by application relation
        List<Map<String, Object>> logs = commonService.findList(materialNamespace + "selectLogsByApplicationId", map);
        ret.put("logs", logs == null ? new java.util.ArrayList<>() : logs);
        return ret;
    }
}


