package org.dromara.zhishu.util;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 纯本地快递公司识别工具
 * 不依赖外部API，基于规则识别
 */
public class ExpressCompanyDetector {

    // 快递公司信息类
    public static class ExpressInfo {
        private String code;      // 公司编码
        private String name;      // 公司名称

        public ExpressInfo(String code, String name) {
            this.code = code;
            this.name = name;
        }

        public String getCode() { return code; }
        public String getName() { return name; }

    }

    // 快递公司规则定义
    private static class ExpressRule {
        String code;
        String name;
        List<Pattern> patterns;
        int priority; // 优先级，数字越小优先级越高

        ExpressRule(String code, String name, String[] regexes, int priority) {
            this.code = code;
            this.name = name;
            this.patterns = new ArrayList<>();
            for (String regex : regexes) {
                this.patterns.add(Pattern.compile(regex));
            }
            this.priority = priority;
        }

        boolean matches(String trackingNumber) {
            for (Pattern pattern : patterns) {
                if (pattern.matcher(trackingNumber).matches()) {
                    return true;
                }
            }
            return false;
        }
    }

    // 规则库（按优先级排序）
    private static final List<ExpressRule> RULES = new ArrayList<>();

    static {
        // 初始化规则库（规则越具体，优先级越高）
        initializeRules();
    }

    private static void initializeRules() {
        // 高优先级规则：精确匹配的特定规则

        // 1. 中通快递 (ZTO)
        RULES.add(new ExpressRule("zhongtong", "中通快递", new String[]{
                "^78\\d{12}$",                     // 14位，78开头（你的例子）
                "^7[3-8]\\d{11}$",                 // 13位，73-78开头
                "^7[3-8]\\d{9}$",                  // 11位，73-78开头
                "^ZTO\\d{10,}$",                   // ZTO开头
                "^ZT\\d{10,}$",                    // ZT开头
                "^75\\d{8}$",                      // 10位，75开头
                "^73\\d{10}$",                     // 12位，73开头
                "^77\\d{10}$",                     // 12位，77开头
                "^\\d{10}$",                       // 10位纯数字（中通常见）
                "^\\d{12}$"                        // 12位纯数字（中通常见）
        }, 1));

        // 2. 顺丰速运 (SF)
        RULES.add(new ExpressRule("shunfeng", "顺丰速运", new String[]{
                "^SF\\d{13}$",                     // SF+13位数字
                "^SF\\d{10}$",                     // SF+10位数字
                "^1[0-2]\\d{10}$",                 // 10、11、12开头+10位数字
                "^00\\d{10}$",                     // 00开头+10位数字
                "^118\\d{9}$",                     // 118开头+9位数字
                "^SF\\w{2}\\d{8}$",                // SF+2字母+8数字
                "^SF\\d{12}$"                      // SF+12位数字
        }, 1));

        // 3. 圆通速递 (YTO)
        RULES.add(new ExpressRule("yuantong", "圆通速递", new String[]{
                "^YT\\d{10,}$",                    // YT开头
                "^YTO\\d{10,}$",                   // YTO开头
                "^8[0-6]\\d{8}$",                  // 80-86开头+8位数字（10位）
                "^8[0-6]\\d{10}$",                 // 80-86开头+10位数字（12位）
                "^1[0-9]\\d{11}$",                 // 10-19开头+11位数字（13位）
                "^[DV]\\d{10}$",                   // D或V开头+10位数字
                "^Y\\d{10}$"                       // Y开头+10位数字
        }, 2));

        // 4. 申通快递 (STO)
        RULES.add(new ExpressRule("shentong", "申通快递", new String[]{
                "^ST\\d{10,}$",                    // ST开头
                "^STO\\d{10,}$",                   // STO开头
                "^SHEX\\d{8,}$",                   // SHEX开头
                "^7[7-8]\\d{10}$",                 // 77或78开头+10位数字（12位）
                "^33\\d{10}$",                     // 33开头+10位数字
                "^55\\d{10}$",                     // 55开头+10位数字
                "^66\\d{10}$",                     // 66开头+10位数字
                "^88\\d{10}$"                      // 88开头+10位数字
        }, 2));

        // 5. 韵达快递 (YD)
        RULES.add(new ExpressRule("yunda", "韵达快递", new String[]{
                "^YD\\d{10,}$",                    // YD开头
                "^YUNDA\\d{8,}$",                  // YUNDA开头
                "^39\\d{11}$",                     // 39开头+11位数字（13位）
                "^19\\d{11}$",                     // 19开头+11位数字
                "^15\\d{11}$",                     // 15开头+11位数字
                "^55\\d{11}$",                     // 55开头+11位数字
                "^17\\d{11}$",                     // 17开头+11位数字
                "^1[2-9]\\d{11}$",                 // 12-19开头+11位数字
                "^\\d{13}$"                        // 13位纯数字
        }, 2));

        // 6. 京东物流 (JD)
        RULES.add(new ExpressRule("jd", "京东物流", new String[]{
                "^JD\\d{10,}$",                    // JD开头
                "^JDX\\d{9,}$",                    // JDX开头
                "^JDL\\d{9,}$",                    // JDL开头
                "^JDV\\d{9,}$",                    // JDV开头
                "^VA\\d{9}$",                      // VA开头+9位数字
                "^JD\\d{11}$",                     // JD+11位数字
                "^J\\d{12}$"                       // J+12位数字
        }, 3));

        // 7. 极兔速递 (JT)
        RULES.add(new ExpressRule("jtexpress", "极兔速递", new String[]{
                "^JT\\d{10,}$",                    // JT开头
                "^JTSD\\d{8,}$",                   // JTSD开头
                "^JITU\\d{8,}$",                   // JITU开头
                "^JT\\d{12}$",                     // JT+12位数字
                "^J\\d{13}$"                       // J+13位数字
        }, 3));

        // 8. 邮政EMS (EMS)
        RULES.add(new ExpressRule("ems", "邮政EMS", new String[]{
                "^1\\d{12}$",                      // 1开头+12位数字（13位）
                "^E\\d{13}$",                      // E开头+13位数字
                "^9[0-9]\\d{10}$",                 // 90-99开头+10位数字（12位）
                "^EMS\\d{9,}$",                    // EMS开头
                "^9\\d{11}$",                      // 9开头+11位数字（12位）
                "^CN\\d{13}$"                      // CN开头+13位数字
        }, 3));

        // 9. 百世快递 (BS)
        RULES.add(new ExpressRule("baishiwuliu", "百世快递", new String[]{
                "^BS\\d{9,}$",                     // BS开头
                "^HT\\d{9,}$",                     // HT开头
                "^HTKY\\d{8,}$",                   // HTKY开头
                "^12\\d{10}$",                     // 12开头+10位数字
                "^A\\d{10}$",                      // A开头+10位数字
                "^\\d{12}$"                        // 12位纯数字（默认）
        }, 4));

        // 10. 德邦快递 (DBL)
        RULES.add(new ExpressRule("debangwuliu", "德邦快递", new String[]{
                "^DB\\d{9,}$",                     // DB开头
                "^DBL\\d{8,}$",                    // DBL开头
                "^DEPPON\\d{8,}$",                 // DEPPON开头
                "^[0-9]{8}$",                      // 8位纯数字
                "^[0-9]{10}$",                     // 10位纯数字
                "^[0-9]{12}$",                     // 12位纯数字
                "^5\\d{9}$"                        // 5开头+9位数字
        }, 4));

        // 11. 其他快递公司（优先级较低）
        RULES.add(new ExpressRule("zhaijisong", "宅急送", new String[]{
                "^ZJS\\d{9,}$"                     // ZJS开头
        }, 5));

        RULES.add(new ExpressRule("guoeryue", "天天快递", new String[]{
                "^TT\\d{9,}$",                     // TT开头
                "^6\\d{9}$"                        // 6开头+9位数字
        }, 5));

        RULES.add(new ExpressRule("qf", "全峰快递", new String[]{
                "^QF\\d{9,}$",                     // QF开头
                "^QFKD\\d{8,}$"                    // QFKD开头
        }, 5));

        RULES.add(new ExpressRule("uc", "优速快递", new String[]{
                "^UC\\d{9,}$"                      // UC开头
        }, 5));

        RULES.add(new ExpressRule("yz", "邮政包裹", new String[]{
                "^9\\d{11}$",                      // 9开头+11位数字
                "^YZ\\d{10,}$"                     // YZ开头
        }, 5));
    }

    /**
     * 识别快递公司（主方法）
     * @param trackingNumber 快递单号
     * @return ExpressInfo对象，包含公司信息和置信度
     */
    public static ExpressInfo detect(String trackingNumber) {
        if (trackingNumber == null || trackingNumber.trim().isEmpty()) {
            return new ExpressInfo("unknown", "未知快递");
        }

        String cleanNumber = trackingNumber.trim().toUpperCase();

        // 1. 首先尝试精确匹配（高优先级规则）
        for (ExpressRule rule : RULES) {
            if (rule.matches(cleanNumber)) {
                return new ExpressInfo(rule.code, rule.name);
            }
        }

        // 2. 如果没有精确匹配，尝试模糊匹配
        ExpressInfo fuzzyMatch = fuzzyDetect(cleanNumber);
        if (fuzzyMatch != null) {
            return fuzzyMatch;
        }

        // 3. 最终无法识别
        return new ExpressInfo("unknown", "未知快递");
    }

    /**
     * 模糊匹配（当精确匹配失败时使用）
     */
    private static ExpressInfo fuzzyDetect(String trackingNumber) {
        // 纯数字单号的模糊识别
        if (trackingNumber.matches("^\\d+$")) {
            return detectNumericOnly(trackingNumber);
        }

        // 包含字母的模糊识别
        if (trackingNumber.matches("^[A-Z]+\\d+$")) {
            return detectWithLetters(trackingNumber);
        }

        return null;
    }

    /**
     * 纯数字单号识别
     */
    private static ExpressInfo detectNumericOnly(String number) {
        int length = number.length();
        String prefix2 = length >= 2 ? number.substring(0, 2) : "";
        String prefix3 = length >= 3 ? number.substring(0, 3) : "";

        // 根据长度和前缀猜测
        Map<String, String> commonPatterns = new HashMap<>();

        // 10位单号
        if (length == 10) {
            commonPatterns.put("75", "中通快递");
            commonPatterns.put("73", "中通快递");
            commonPatterns.put("80", "圆通速递");
            commonPatterns.put("82", "圆通速递");
        }

        // 12位单号
        if (length == 12) {
            commonPatterns.put("77", "申通快递");
            commonPatterns.put("88", "申通快递");
            commonPatterns.put("33", "申通快递");
            commonPatterns.put("12", "百世快递");
            commonPatterns.put("39", "韵达快递");
            commonPatterns.put("19", "韵达快递");
        }

        // 13位单号
        if (length == 13) {
            commonPatterns.put("1", "邮政EMS");
            commonPatterns.put("39", "韵达快递");
            commonPatterns.put("19", "韵达快递");
            commonPatterns.put("10", "顺丰速运");
        }

        // 14位单号（你的例子）
        if (length == 14) {
            if (prefix2.equals("78")) {
                return new ExpressInfo("zhongtong", "中通快递");
            }
        }

        // 根据前缀匹配
        for (Map.Entry<String, String> entry : commonPatterns.entrySet()) {
            if (number.startsWith(entry.getKey())) {
                String code = getCodeByName(entry.getValue());
                return new ExpressInfo(code, entry.getValue());
            }
        }

        // 根据长度猜测
        switch (length) {
            case 10: return new ExpressInfo("zhongtong", "中通快递");
            case 12: return new ExpressInfo("baishiwuliu", "百世快递");
            case 13: return new ExpressInfo("ems", "邮政EMS");
            case 14: return new ExpressInfo("zhongtong", "中通快递");
            default: return null;
        }
    }

    /**
     * 包含字母的单号识别
     */
    private static ExpressInfo detectWithLetters(String trackingNumber) {
        // 提取字母前缀
        String prefix = trackingNumber.replaceAll("^(\\D+).*$", "$1");

        Map<String, String> prefixMap = new HashMap<>();
        prefixMap.put("SF", "顺丰速运");
        prefixMap.put("JD", "京东物流");
        prefixMap.put("YT", "圆通速递");
        prefixMap.put("YTO", "圆通速递");
        prefixMap.put("ST", "申通快递");
        prefixMap.put("STO", "申通快递");
        prefixMap.put("ZT", "中通快递");
        prefixMap.put("ZTO", "中通快递");
        prefixMap.put("YD", "韵达快递");
        prefixMap.put("JT", "极兔速递");
        prefixMap.put("EMS", "邮政EMS");
        prefixMap.put("BS", "百世快递");
        prefixMap.put("DB", "德邦快递");
        prefixMap.put("ZJS", "宅急送");
        prefixMap.put("TT", "天天快递");

        for (Map.Entry<String, String> entry : prefixMap.entrySet()) {
            if (prefix.startsWith(entry.getKey())) {
                String code = getCodeByName(entry.getValue());
                return new ExpressInfo(code, entry.getValue());
            }
        }

        return null;
    }

    /**
     * 根据公司名称获取编码
     */
    private static String getCodeByName(String name) {
        Map<String, String> nameToCode = new HashMap<>();
        nameToCode.put("中通快递", "zhongtong");
        nameToCode.put("顺丰速运", "shunfeng");
        nameToCode.put("圆通速递", "yuantong");
        nameToCode.put("申通快递", "shentong");
        nameToCode.put("韵达快递", "yunda");
        nameToCode.put("京东物流", "jd");
        nameToCode.put("极兔速递", "jtexpress");
        nameToCode.put("邮政EMS", "ems");
        nameToCode.put("百世快递", "baishiwuliu");
        nameToCode.put("德邦快递", "debangwuliu");
        nameToCode.put("宅急送", "zhaijisong");
        nameToCode.put("天天快递", "guoeryue");
        nameToCode.put("全峰快递", "qf");
        nameToCode.put("优速快递", "uc");
        nameToCode.put("邮政包裹", "yz");

        return nameToCode.getOrDefault(name, "unknown");
    }

    /**
     * 获取所有支持的快递公司
     */
    public static List<String> getSupportedCompanies() {
        Set<String> companies = new LinkedHashSet<>();
        for (ExpressRule rule : RULES) {
            companies.add(rule.name);
        }
        return new ArrayList<>(companies);
    }
}