package com.yc.ship.module.trade.utils;

import java.util.*;

/**
 * 证件号码解析工具类 - 根据证件号前2位省份码解析省份名称
 * <p>
 * 中国大陆身份证号码前6位为行政区划码，其中前2位代表省份。
 * 港澳台居民居住证同样采用18位编码格式，前2位为大陆居住地省份码。
 * 护照、通行证、回乡证、台胞证、户口本等证件号码格式不同，无法解析省份。
 * </p>
 * <p>
 * 支持解析的证件类型：
 *   1  - 身份证（18位/15位）
 *   11 - 港澳台居民居住证（18位，编码规则同身份证）
 * </p>
 * <p>
 * 不支持解析的证件类型（返回空字符串）：
 *   3  - 港澳台通行证
 *   4  - 护照
 *   5  - 港澳通行证
 *   6  - 台湾通行证
 *   7  - 回乡证（港澳居民来往内地通行证）
 *   8  - 台胞证（台湾居民来往大陆通行证）
 *   10 - 户口本
 * </p>
 *
 * @Author: AI
 * @Date: 2026/05/06
 */
public class IdCardProvinceUtil {

    // ==================== 证件类型常量 ====================
    /** 身份证 */
    public static final int CREDENTIAL_TYPE_ID_CARD = 0;
    /** 港澳台通行证 */
    public static final int CREDENTIAL_TYPE_HK_MACAO_TAIWAN_PASS = 3;
    /** 护照 */
    public static final int CREDENTIAL_TYPE_PASSPORT = 1;
    /** 港澳通行证 */
    public static final int CREDENTIAL_TYPE_HK_MACAO_PASS = 5;
    /** 台湾通行证 */
    public static final int CREDENTIAL_TYPE_TAIWAN_PASS = 6;
    /** 回乡证（港澳居民来往内地通行证） */
    public static final int CREDENTIAL_TYPE_HOME_RETURN_PERMIT = 7;
    /** 台胞证（台湾居民来往大陆通行证） */
    public static final int CREDENTIAL_TYPE_TAIWAN_COMPATRIOT_PERMIT = 8;
    /** 户口本 */
    public static final int CREDENTIAL_TYPE_HOUSEHOLD_REGISTER = 10;
    /** 港澳台居民居住证 */
    public static final int CREDENTIAL_TYPE_HK_MACAO_TAIWAN_RESIDENCE_PERMIT = 11;

    // ==================== 校验常量 ====================
    /** 身份证号码长度（18位） */
    private static final int ID_CARD_LENGTH_18 = 18;
    /** 旧身份证号码长度（15位） */
    private static final int ID_CARD_LENGTH_15 = 15;
    /** 省份码长度（前2位） */
    private static final int PROVINCE_CODE_LENGTH = 2;
    /** 18位身份证号末位校验位可能为X */
    private static final char ID_CARD_X = 'X';
    private static final char ID_CARD_X_LOWER = 'x';

    /**
     * 可以解析省份的证件类型集合（号码格式与身份证相同，采用18位行政区划编码）
     * 身份证(1) 和 港澳台居民居住证(11) 均采用GB 11643编码规则
     */
    private static final Set<Integer> PARSEABLE_CREDENTIAL_TYPES = Collections.unmodifiableSet(
            new HashSet<>(Arrays.asList(CREDENTIAL_TYPE_ID_CARD, CREDENTIAL_TYPE_HK_MACAO_TAIWAN_RESIDENCE_PERMIT))
    );

    /** 省份码 -> 省份名称 映射表（不可变，基于GB/T 2260行政区划代码前2位） */
    private static final Map<String, String> PROVINCE_MAP;

    /** 城市码（前4位） -> 城市名称 映射表（主要城市） */
    private static final Map<String, String> CITY_MAP;

    static {
        Map<String, String> map = new HashMap<>(40);
        map.put("11", "北京");
        map.put("12", "天津");
        map.put("13", "河北");
        map.put("14", "山西");
        map.put("15", "内蒙古");
        map.put("21", "辽宁");
        map.put("22", "吉林");
        map.put("23", "黑龙江");
        map.put("31", "上海");
        map.put("32", "江苏");
        map.put("33", "浙江");
        map.put("34", "安徽");
        map.put("35", "福建");
        map.put("36", "江西");
        map.put("37", "山东");
        map.put("41", "河南");
        map.put("42", "湖北");
        map.put("43", "湖南");
        map.put("44", "广东");
        map.put("45", "广西");
        map.put("46", "海南");
        map.put("50", "重庆");
        map.put("51", "四川");
        map.put("52", "贵州");
        map.put("53", "云南");
        map.put("54", "西藏");
        map.put("61", "陕西");
        map.put("62", "甘肃");
        map.put("63", "青海");
        map.put("64", "宁夏");
        map.put("65", "新疆");
        map.put("71", "台湾");
        map.put("81", "香港");
        map.put("82", "澳门");
        // 91开头的为国外身份证件，无对应省份
        PROVINCE_MAP = Collections.unmodifiableMap(map);

        Map<String, String> cityMap = new HashMap<>(80);
        // 直辖市
        cityMap.put("1100", "北京"); cityMap.put("1101", "北京");
        cityMap.put("1200", "天津"); cityMap.put("1201", "天津");
        cityMap.put("3100", "上海"); cityMap.put("3101", "上海");
        cityMap.put("5000", "重庆"); cityMap.put("5001", "重庆");
        // 河北
        cityMap.put("1301", "石家庄"); cityMap.put("1302", "唐山"); cityMap.put("1303", "秦皇岛"); cityMap.put("1304", "邯郸");
        // 山西
        cityMap.put("1401", "太原"); cityMap.put("1402", "大同");
        // 内蒙古
        cityMap.put("1501", "呼和浩特"); cityMap.put("1502", "包头");
        // 辽宁
        cityMap.put("2101", "沈阳"); cityMap.put("2102", "大连"); cityMap.put("2103", "鞍山");
        // 吉林
        cityMap.put("2201", "长春"); cityMap.put("2202", "吉林");
        // 黑龙江
        cityMap.put("2301", "哈尔滨"); cityMap.put("2302", "齐齐哈尔");
        // 江苏
        cityMap.put("3201", "南京"); cityMap.put("3202", "无锡"); cityMap.put("3203", "徐州");
        cityMap.put("3204", "常州"); cityMap.put("3205", "苏州"); cityMap.put("3206", "南通");
        cityMap.put("3207", "连云港"); cityMap.put("3208", "淮安"); cityMap.put("3209", "盐城");
        cityMap.put("3210", "扬州"); cityMap.put("3211", "镇江"); cityMap.put("3212", "泰州"); cityMap.put("3213", "宿迁");
        // 浙江
        cityMap.put("3301", "杭州"); cityMap.put("3302", "宁波"); cityMap.put("3303", "温州");
        cityMap.put("3304", "嘉兴"); cityMap.put("3305", "湖州"); cityMap.put("3306", "绍兴");
        cityMap.put("3307", "金华"); cityMap.put("3308", "衢州"); cityMap.put("3309", "舟山");
        cityMap.put("3310", "台州"); cityMap.put("3311", "丽水");
        // 安徽
        cityMap.put("3401", "合肥"); cityMap.put("3402", "芜湖"); cityMap.put("3403", "蚌埠"); cityMap.put("3404", "淮南");
        cityMap.put("3405", "马鞍山"); cityMap.put("3406", "淮北"); cityMap.put("3407", "铜陵"); cityMap.put("3408", "安庆");
        // 福建
        cityMap.put("3501", "福州"); cityMap.put("3502", "厦门"); cityMap.put("3503", "莆田"); cityMap.put("3504", "三明");
        cityMap.put("3505", "泉州"); cityMap.put("3506", "漳州"); cityMap.put("3507", "南平"); cityMap.put("3508", "龙岩"); cityMap.put("3509", "宁德");
        // 江西
        cityMap.put("3601", "南昌"); cityMap.put("3602", "景德镇"); cityMap.put("3603", "萍乡"); cityMap.put("3604", "九江");
        cityMap.put("3605", "新余"); cityMap.put("3606", "鹰潭"); cityMap.put("3607", "赣州"); cityMap.put("3608", "吉安");
        cityMap.put("3609", "宜春"); cityMap.put("3610", "抚州"); cityMap.put("3611", "上饶");
        // 山东
        cityMap.put("3701", "济南"); cityMap.put("3702", "青岛"); cityMap.put("3703", "淄博"); cityMap.put("3704", "枣庄");
        cityMap.put("3705", "东营"); cityMap.put("3706", "烟台"); cityMap.put("3707", "潍坊"); cityMap.put("3708", "济宁");
        cityMap.put("3709", "泰安"); cityMap.put("3710", "威海"); cityMap.put("3711", "日照"); cityMap.put("3713", "临沂");
        // 河南
        cityMap.put("4101", "郑州"); cityMap.put("4102", "开封"); cityMap.put("4103", "洛阳"); cityMap.put("4104", "平顶山");
        cityMap.put("4105", "安阳"); cityMap.put("4106", "鹤壁"); cityMap.put("4107", "新乡"); cityMap.put("4108", "焦作");
        cityMap.put("4109", "濮阳"); cityMap.put("4110", "许昌"); cityMap.put("4111", "漯河"); cityMap.put("4112", "三门峡");
        cityMap.put("4113", "南阳"); cityMap.put("4114", "商丘"); cityMap.put("4115", "信阳"); cityMap.put("4116", "周口"); cityMap.put("4117", "驻马店");
        // 湖北
        cityMap.put("4201", "武汉"); cityMap.put("4202", "黄石"); cityMap.put("4203", "十堰"); cityMap.put("4205", "宜昌");
        cityMap.put("4206", "襄阳"); cityMap.put("4207", "鄂州"); cityMap.put("4208", "荆门"); cityMap.put("4209", "孝感");
        cityMap.put("4210", "荆州"); cityMap.put("4211", "黄冈"); cityMap.put("4212", "咸宁"); cityMap.put("4213", "随州");
        cityMap.put("4228", "恩施");
        // 湖南
        cityMap.put("4301", "长沙"); cityMap.put("4302", "株洲"); cityMap.put("4303", "湘潭"); cityMap.put("4304", "衡阳");
        cityMap.put("4305", "邵阳"); cityMap.put("4306", "岳阳"); cityMap.put("4307", "常德"); cityMap.put("4308", "张家界");
        cityMap.put("4309", "益阳"); cityMap.put("4310", "郴州"); cityMap.put("4311", "永州"); cityMap.put("4312", "怀化");
        cityMap.put("4313", "娄底"); cityMap.put("4331", "湘西");
        // 广东
        cityMap.put("4401", "广州"); cityMap.put("4402", "韶关"); cityMap.put("4403", "深圳"); cityMap.put("4404", "珠海");
        cityMap.put("4405", "汕头"); cityMap.put("4406", "佛山"); cityMap.put("4407", "江门"); cityMap.put("4408", "湛江");
        cityMap.put("4409", "茂名"); cityMap.put("4412", "肇庆"); cityMap.put("4413", "惠州"); cityMap.put("4414", "梅州");
        cityMap.put("4415", "汕尾"); cityMap.put("4416", "河源"); cityMap.put("4417", "阳江"); cityMap.put("4418", "清远");
        cityMap.put("4419", "东莞"); cityMap.put("4420", "中山"); cityMap.put("4451", "潮州"); cityMap.put("4452", "揭阳"); cityMap.put("4453", "云浮");
        // 广西
        cityMap.put("4501", "南宁"); cityMap.put("4502", "柳州"); cityMap.put("4503", "桂林"); cityMap.put("4504", "梧州");
        cityMap.put("4505", "北海"); cityMap.put("4506", "防城港"); cityMap.put("4507", "钦州"); cityMap.put("4508", "贵港");
        cityMap.put("4509", "玉林"); cityMap.put("4510", "百色"); cityMap.put("4511", "贺州"); cityMap.put("4512", "河池");
        cityMap.put("4513", "来宾"); cityMap.put("4514", "崇左");
        // 海南
        cityMap.put("4601", "海口"); cityMap.put("4602", "三亚"); cityMap.put("4604", "儋州");
        // 四川
        cityMap.put("5101", "成都"); cityMap.put("5103", "自贡"); cityMap.put("5104", "攀枝花"); cityMap.put("5105", "泸州");
        cityMap.put("5106", "德阳"); cityMap.put("5107", "绵阳"); cityMap.put("5108", "广元"); cityMap.put("5109", "遂宁");
        cityMap.put("5110", "内江"); cityMap.put("5111", "乐山"); cityMap.put("5113", "南充"); cityMap.put("5114", "眉山");
        cityMap.put("5115", "宜宾"); cityMap.put("5116", "广安"); cityMap.put("5117", "达州"); cityMap.put("5118", "雅安");
        cityMap.put("5119", "巴中"); cityMap.put("5120", "资阳"); cityMap.put("5132", "阿坝"); cityMap.put("5133", "甘孜"); cityMap.put("5134", "凉山");
        // 贵州
        cityMap.put("5201", "贵阳"); cityMap.put("5202", "六盘水"); cityMap.put("5203", "遵义"); cityMap.put("5204", "安顺");
        cityMap.put("5205", "毕节"); cityMap.put("5206", "铜仁"); cityMap.put("5223", "黔西南"); cityMap.put("5226", "黔东南"); cityMap.put("5227", "黔南");
        // 云南
        cityMap.put("5301", "昆明"); cityMap.put("5303", "曲靖"); cityMap.put("5304", "玉溪"); cityMap.put("5305", "保山");
        cityMap.put("5306", "昭通"); cityMap.put("5307", "丽江"); cityMap.put("5308", "普洱"); cityMap.put("5309", "临沧");
        cityMap.put("5323", "楚雄"); cityMap.put("5325", "红河"); cityMap.put("5326", "文山"); cityMap.put("5328", "西双版纳");
        cityMap.put("5329", "大理"); cityMap.put("5331", "德宏"); cityMap.put("5333", "怒江"); cityMap.put("5334", "迪庆");
        // 西藏
        cityMap.put("5401", "拉萨"); cityMap.put("5402", "日喀则"); cityMap.put("5403", "昌都"); cityMap.put("5404", "林芝");
        cityMap.put("5405", "山南"); cityMap.put("5406", "那曲"); cityMap.put("5425", "阿里");
        // 陕西
        cityMap.put("6101", "西安"); cityMap.put("6102", "铜川"); cityMap.put("6103", "宝鸡"); cityMap.put("6104", "咸阳");
        cityMap.put("6105", "渭南"); cityMap.put("6106", "延安"); cityMap.put("6107", "汉中"); cityMap.put("6108", "榆林");
        cityMap.put("6109", "安康"); cityMap.put("6110", "商洛");
        // 甘肃
        cityMap.put("6201", "兰州"); cityMap.put("6202", "嘉峪关"); cityMap.put("6203", "金昌"); cityMap.put("6204", "白银");
        cityMap.put("6205", "天水"); cityMap.put("6206", "武威"); cityMap.put("6207", "张掖"); cityMap.put("6208", "平凉");
        cityMap.put("6209", "酒泉"); cityMap.put("6210", "庆阳"); cityMap.put("6211", "定西"); cityMap.put("6212", "陇南");
        // 青海
        cityMap.put("6301", "西宁"); cityMap.put("6302", "海东"); cityMap.put("6322", "海北"); cityMap.put("6323", "黄南");
        cityMap.put("6325", "海南"); cityMap.put("6326", "果洛"); cityMap.put("6327", "玉树"); cityMap.put("6328", "海西");
        // 宁夏
        cityMap.put("6401", "银川"); cityMap.put("6402", "石嘴山"); cityMap.put("6403", "吴忠"); cityMap.put("6404", "固原"); cityMap.put("6405", "中卫");
        // 新疆
        cityMap.put("6501", "乌鲁木齐"); cityMap.put("6502", "克拉玛依"); cityMap.put("6504", "吐鲁番"); cityMap.put("6505", "哈密");
        cityMap.put("6523", "昌吉"); cityMap.put("6527", "博尔塔拉"); cityMap.put("6528", "巴音郭楞"); cityMap.put("6529", "阿克苏");
        cityMap.put("6530", "克孜勒苏"); cityMap.put("6531", "喀什"); cityMap.put("6532", "和田"); cityMap.put("6540", "伊犁");
        cityMap.put("6542", "塔城"); cityMap.put("6543", "阿勒泰"); cityMap.put("6590", "自治区直辖县级");
        // 港澳台
        cityMap.put("7100", "台湾"); cityMap.put("8100", "香港"); cityMap.put("8200", "澳门");
        CITY_MAP = Collections.unmodifiableMap(cityMap);
    }

    /**
     * 根据证件类型和证件号解析省份名称
     * <p>
     * 身份证(1)和港澳台居民居住证(11)：通过号码前2位省份码解析；
     * 台湾通行证(6)和台胞证(8)：直接返回"台湾"；
     * 其他证件类型（护照、港澳通行证等）：返回空字符串。
     * </p>
     *
     * @param credentialType 证件类型
     * @param credentialNo   证件号码
     * @return 省份名称，无法解析时返回空字符串
     */
    public static String getProvinceName(Integer credentialType, String credentialNo, String  nationalityName) {
        if (credentialType == null) {
            return "";
        }
        // 台湾通行证、台胞证 → 直接返回"台湾"
        if (credentialType == CREDENTIAL_TYPE_TAIWAN_PASS
                || credentialType == CREDENTIAL_TYPE_TAIWAN_COMPATRIOT_PERMIT) {
            return "台湾";
        }

        if (nationalityName.contains("香港")) {
            return "香港";
        }

        if (nationalityName.contains("澳门")) {
            return "澳门";
        }
        // 非可解析的证件类型，直接返回空
        if (!PARSEABLE_CREDENTIAL_TYPES.contains(credentialType)  && !"中国".equals(nationalityName)) {
            return "";
        }
        // 证件号为空或长度不足，无法解析
        if (credentialNo == null || credentialNo.trim().length() < PROVINCE_CODE_LENGTH) {
            return "";
        }
        String trimmedNo = credentialNo.trim();
        // 校验号码格式
        if (!isValidIdCardFormat(trimmedNo) && !"中国".equals(nationalityName)) {
            return "";
        }
        // 提取省份码（前2位）并查表
        String provinceCode = trimmedNo.substring(0, PROVINCE_CODE_LENGTH);
        return PROVINCE_MAP.getOrDefault(provinceCode, "其他");
    }

    /**
     * 校验号码是否符合身份证编码格式
     * <p>
     * 18位：前17位必须为数字，第18位可为数字或X/x
     * 15位：全部必须为数字
     * </p>
     *
     * @param idCardNo 证件号码（已trim）
     * @return 格式是否合法
     */
    private static boolean isValidIdCardFormat(String idCardNo) {
        int len = idCardNo.length();
        if (len == ID_CARD_LENGTH_18) {
            // 前17位必须为数字
            String first17 = idCardNo.substring(0, 17);
            if (!isNumeric(first17)) {
                return false;
            }
            // 第18位可为数字或X/x
            char lastChar = idCardNo.charAt(17);
            return Character.isDigit(lastChar) || lastChar == ID_CARD_X || lastChar == ID_CARD_X_LOWER;
        } else if (len == ID_CARD_LENGTH_15) {
            // 15位旧身份证：全部为数字
            return isNumeric(idCardNo);
        }
        return false;
    }

    /**
     * 根据证件类型和证件号解析城市名称
     * <p>
     * 仅支持身份证(0)和港澳台居民居住证(11)：通过号码前4位城市码解析；
     * 其他证件类型返回空字符串。
     * </p>
     *
     * @param credentialType 证件类型
     * @param credentialNo   证件号码
     * @return 城市名称，无法解析时返回空字符串
     */
    public static String getCityName(Integer credentialType, String credentialNo) {
        if (credentialType == null) {
            return "";
        }
        // 非可解析的证件类型，直接返回空
        if (!PARSEABLE_CREDENTIAL_TYPES.contains(credentialType)) {
            return "";
        }
        // 证件号为空或长度不足，无法解析
        if (credentialNo == null || credentialNo.trim().length() < 4) {
            return "";
        }
        String trimmedNo = credentialNo.trim();
        // 校验号码格式
        if (!isValidIdCardFormat(trimmedNo)) {
            return "";
        }
        // 提取城市码（前4位）并查表
        String cityCode = trimmedNo.substring(0, 4);
        String cityName = CITY_MAP.get(cityCode);
        if (cityName != null) {
            return cityName;
        }
        // 如果前4位找不到，尝试用前2位+"00"查找直辖市/省级市
        String provinceCode = trimmedNo.substring(0, 2);
        return CITY_MAP.getOrDefault(provinceCode + "00", "");
    }

    /**
     * 判断字符串是否全部由数字组成
     */
    private static boolean isNumeric(String str) {
        for (int i = 0, len = str.length(); i < len; i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}
