package com.chinaweal.aiccs.common.util;

import com.chinaweal.aiccs.aiccs.abnormal.entity.CaseZfReport;
import com.chinaweal.aiccs.aiccs.abnormal.service.CaseZfReportService;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 案件编号生成工具类
 *
 * 22位编码规则：9位市场监督管理局代码 + 1位分类码 + 8位登记日期 + 4位流水号
 * 分类码：1-行政处罚案件，2-行政复议案件，3-行政诉讼案件，4-行政赔偿案件
 *
 * @author lwd
 * @since 2025-10-29
 */
@Slf4j
@Component
public class CaseNoGenerator {

    @Resource
    private CaseZfReportService caseZfReportService;

    /**
     * 分类码映射
     */
    private static final Map<String, String> CATEGORY_CODE_MAP = new HashMap<>();
    static {
        CATEGORY_CODE_MAP.put("行政处罚案件", "1");
        CATEGORY_CODE_MAP.put("行政复议案件", "2");
        CATEGORY_CODE_MAP.put("行政诉讼案件", "3");
        CATEGORY_CODE_MAP.put("行政赔偿案件", "4");
    }

    /**
     * 生成唯一的案件编号
     *
     * @param reportCase 行政处罚案件数据
     * @param existingCaseNos 数据库中已存在的案件编号
     * @return 唯一的22位案件编号
     */
    public String generateUniqueCaseNo(CaseZfReport reportCase, Set<String> existingCaseNos) {
        try {
            // 1. 提取市场监督管理局代码（案件编号前6位 + 3个0）
            String marketSupervisionCode = extractMarketSupervisionCode(reportCase);

            // 2. 确定分类码（默认为1，表示行政处罚案件）
            String categoryCode = "1"; // 行政处罚案件

            // 3. 提取登记日期（格式：yyyyMMdd）
            String registerDate = extractRegisterDate(reportCase);

            // 4. 生成流水号（5001-9999）
            String serialNumber = generateSerialNumber(marketSupervisionCode, categoryCode, registerDate, existingCaseNos);

            // 5. 组装完整的22位案件编号
            String caseNo = marketSupervisionCode + categoryCode + registerDate + serialNumber;

            log.info("生成案件编号: {} (市场监管局代码:{}, 分类码:{}, 登记日期:{}, 流水号:{})",
                caseNo, marketSupervisionCode, categoryCode, registerDate, serialNumber);

            return caseNo;

        } catch (Exception e) {
            log.error("生成案件编号失败", e);
            throw new BusinessException("生成案件编号失败: " + e.getMessage());
        }
    }

    /**
     * 提取市场监督管理局代码（9位）
     * 规则：案件编号前6位 + 3个0
     */
    private String extractMarketSupervisionCode(CaseZfReport reportCase) {
        String originalCaseNo = reportCase.getCaseno();
        if (originalCaseNo == null || originalCaseNo.length() < 6) {
            // 如果原案件编号为空或长度不足，使用默认值
            return "150000000"; // 默认内蒙市监局
        }

        String front6Code = originalCaseNo.substring(0, 6);
        return front6Code + "000";
    }

    /**
     * 提取登记日期（8位，格式：yyyyMMdd）
     */
    private String extractRegisterDate(CaseZfReport reportCase) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        // 优先使用办案日期
        if (reportCase.getCasefidate() != null) {
            return sdf.format(reportCase.getCasefidate());
        }

        // 如果办案日期为空，使用当前日期
        return sdf.format(new Date());
    }

    /**
     * 生成流水号（4位，范围：5001-9999）
     * 如果当天流水号用完，向前查找有空余流水号的日期
     */
    private String generateSerialNumber(String marketSupervisionCode, String categoryCode, String registerDate, Set<String> existingCaseNos) {
        // 从当前日期开始，向前查找可用流水号
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Date targetDate = null;
        try {
            targetDate = sdf.parse(registerDate);
        } catch (Exception e) {
            log.error("解析登记日期失败: {}", registerDate, e);
            targetDate = new Date();
        }

        // 最多向前查找30天
        for (int dayOffset = 0; dayOffset < 30; dayOffset++) {
            String checkDate = sdf.format(calculateDate(targetDate, -dayOffset));

            // 查询该日期已使用的流水号
            Set<Integer> usedSerialNumbers = getUsedSerialNumbersForDate(
                marketSupervisionCode, categoryCode, checkDate, existingCaseNos);

            // 尝试生成可用的流水号（5001-9999）
            for (int serial = 5001; serial <= 9999; serial++) {
                if (!usedSerialNumbers.contains(serial)) {
                    String candidateCaseNo = marketSupervisionCode + categoryCode + checkDate + String.format("%04d", serial);
                    if (!existingCaseNos.contains(candidateCaseNo)) {
                        log.info("找到可用流水号: {} (日期: {})", serial, checkDate);
                        return String.format("%04d", serial);
                    }
                }
            }

            log.warn("日期 {} 的流水号已用完，继续查找前一天", checkDate);
        }

        throw new BusinessException("无法生成唯一流水号，请联系系统管理员");
    }

    /**
     * 计算日期偏移
     */
    private Date calculateDate(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, days);
        return calendar.getTime();
    }

    /**
     * 获取指定日期已使用的流水号
     */
    private Set<Integer> getUsedSerialNumbersForDate(String marketSupervisionCode, String categoryCode,
                                                   String checkDate, Set<String> existingCaseNos) {
        Set<Integer> usedSerialNumbers = new HashSet<>();

        String prefix = marketSupervisionCode + categoryCode + checkDate;

        for (String caseNo : existingCaseNos) {
            if (caseNo != null && caseNo.startsWith(prefix) && caseNo.length() == 22) {
                String serialStr = caseNo.substring(18, 22);
                try {
                    int serial = Integer.parseInt(serialStr);
                    if (serial >= 5001 && serial <= 9999) {
                        usedSerialNumbers.add(serial);
                    }
                } catch (NumberFormatException e) {
                    // 忽略非数字流水号
                }
            }
        }

        return usedSerialNumbers;
    }

    /**
     * 批量生成唯一案件编号
     *
     * @param reportList 行政处罚案件列表
     * @return 案件编号映射Map
     */
    public Map<CaseZfReport, String> batchGenerateUniqueCaseNos(List<CaseZfReport> reportList) {
        Map<CaseZfReport, String> resultMap = new HashMap<>();

        // 获取数据库中已存在的所有案件编号
        Set<String> existingCaseNos = getAllExistingCaseNos();

        // 按办案日期和业务序列号分组
        Map<String, List<CaseZfReport>> groupedReports = groupReportsByDateAndBizSeq(reportList);

        for (Map.Entry<String, List<CaseZfReport>> entry : groupedReports.entrySet()) {
            List<CaseZfReport> groupReports = entry.getValue();

            // 按业务序列号排序
            groupReports.sort((r1, r2) -> {
                String bizSeq1 = r1.getBizseq() != null ? r1.getBizseq() : "";
                String bizSeq2 = r2.getBizseq() != null ? r2.getBizseq() : "";
                return bizSeq1.compareTo(bizSeq2);
            });

            // 为每个案件生成唯一编号
            for (CaseZfReport report : groupReports) {
                String uniqueCaseNo = generateUniqueCaseNo(report, existingCaseNos);
                resultMap.put(report, uniqueCaseNo);
                existingCaseNos.add(uniqueCaseNo); // 添加到已存在集合，避免重复
            }
        }

        log.info("批量生成案件编号完成，共生成 {} 个", resultMap.size());
        return resultMap;
    }

    /**
     * 按办案日期和业务序列号分组
     */
    private Map<String, List<CaseZfReport>> groupReportsByDateAndBizSeq(List<CaseZfReport> reportList) {
        Map<String, List<CaseZfReport>> groupedMap = new TreeMap<>(); // 使用TreeMap按日期排序

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        for (CaseZfReport report : reportList) {
            String groupKey;

            if (report.getCasefidate() != null) {
                groupKey = sdf.format(report.getCasefidate());
            } else {
                groupKey = sdf.format(new Date());
            }

            groupedMap.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(report);
        }

        return groupedMap;
    }

    /**
     * 获取数据库中已存在的所有案件编号
     */
    private Set<String> getAllExistingCaseNos() {
        Set<String> existingCaseNos = new HashSet<>();

        try {
            // 分批查询，避免内存溢出
            int pageSize = 1000;
            int offset = 0;

            while (true) {
                List<CaseZfReport> batch = caseZfReportService.queryCaseListByCondition(createBatchQueryParams(offset, pageSize));

                if (batch == null || batch.isEmpty()) {
                    break;
                }

                for (CaseZfReport report : batch) {
                    if (report.getCaseno() != null) {
                        existingCaseNos.add(report.getCaseno());
                    }
                }

                offset += pageSize;
            }

            log.info("已加载 {} 个现有案件编号到内存", existingCaseNos.size());

        } catch (Exception e) {
            log.error("获取现有案件编号失败", e);
            // 返回空集合，允许继续执行
        }

        return existingCaseNos;
    }

    /**
     * 创建批量查询参数
     */
    private Map<String, Object> createBatchQueryParams(int offset, int pageSize) {
        Map<String, Object> params = new HashMap<>();
        params.put("offset", offset);
        params.put("pageSize", pageSize);
        return params;
    }
}
