package cn.iocoder.yudao.framework.common.util.validation;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberToCarrierMapper;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.log4j.Log4j2;

import java.util.List;
import java.util.Locale;
import java.util.Objects;

@Log4j2
public class PhoneUtil {

    private static PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();

    private static PhoneNumberToCarrierMapper carrierMapper = PhoneNumberToCarrierMapper.getInstance();

    private static PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();

    public static final int CHINA_COUNTRY_CODE = 86;

    public static final String PROVINCE_REG = "[\\u4E00-\\u9FFF]+?(?:省|自治区|特别行政区)|(?:天津|重庆|上海|北京)市";
    public static final String CITY_REG = "(?<=省|自治区|特别行政区)[\u4E00-\u9FFF]+?(?:市|自治州|区|县|盟)";

    /**
     * 根据国家代码和手机号  判断手机号是否有效
     * phoneNumber
     * countryCode
     * 手机号是否有效
     */
    public static boolean checkPhoneNumber(String phoneNumber, String countryCode) {
        int code = NumberUtil.parseInt(countryCode);
        long phone = NumberUtil.parseLong(phoneNumber);
        PhoneNumber pn = new PhoneNumber();
        pn.setCountryCode(code);
        pn.setNationalNumber(phone);
        return phoneNumberUtil.isValidNumber(pn);

    }

    /**
     * 获取运营商
     */
    public static String getOperator(String phoneNumber, Integer countryCode) {
        long phone = NumberUtil.parseLong(phoneNumber);
        PhoneNumber pn = new PhoneNumber();
        pn.setCountryCode(countryCode);
        pn.setNationalNumber(phone);
        //返回结果只有英文，自己转成成中文
        String carrierEn = carrierMapper.getNameForNumber(pn, Locale.ENGLISH);
        String carrierZh = "";
        carrierZh += geocoder.getDescriptionForNumber(pn, Locale.CHINESE);
        switch (carrierEn) {
            case "China Mobile":
                carrierZh += "移动";
                break;
            case "China Unicom":
                carrierZh += "联通";
                break;
            case "China Telecom":
                carrierZh += "电信";
                break;
            default:
                break;
        }
        return carrierZh;
    }

    /**
     * 获取运营商,中国
     */
    public static String getOperator(String phoneNumber) {
        return getOperator(phoneNumber, CHINA_COUNTRY_CODE);
    }


    /**
     * 获取归属地
     */
    public static String getGeo(String phoneNumber, Integer countryCode) {
        long phone = NumberUtil.parseLong(phoneNumber);
        PhoneNumber pn = new PhoneNumber();
        pn.setCountryCode(countryCode);
        pn.setNationalNumber(phone);
        return geocoder.getDescriptionForNumber(pn, Locale.CHINESE);
    }

    //获取归属地，中国
    public static String getGeo(String phoneNumber) {
        return getGeo(phoneNumber, CHINA_COUNTRY_CODE);
    }

    public static Area getArea(String phoneNumber) {
        String address = getGeo(phoneNumber);
        if (address != null) {
            String province = ReUtil.getGroup0(PROVINCE_REG, address);
            String city = ReUtil.getGroup0(CITY_REG, address);
            return new Area().setProvince(province).setCity(city);

        }
        return new Area().setProvince("未知").setCity("未知");
    }


    public static String formatPhone(String mobileCode) {
        PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
        PhoneNumber numberProto;
        String[] mc = mobileCode.split(StrUtil.COLON);
        if (mc.length != 2) {
            return "";
        }
        String code = mc[0]; // 国家区号
        String mobile = mc[1]; // 手机号
        // TODO 所有调用原手机号返回,格式化方法有bug,暂不使用, 号码库的格式化,只是将号码变为国际通用格式,不一定是去0
        return mobile;
//        if (StringUtils.equals(code, "233") || StringUtils.equals(code, "225")) {
//            return mobile;
//        }
//        try {
//            numberProto = phoneUtil.parse("+".concat(code).concat(mobile), "");
//        } catch (NumberParseException e) {
//            return "";
//        }
//        String formattedNumber = phoneUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
//        System.out.println("Formatted number: " + formattedNumber);
//        String number = PhoneNumberUtil.normalizeDigitsOnly(formattedNumber);
//        System.out.println("Formatted number: " + number);
//        return number;
    }


    public static boolean isMobileCode(String mobileCode) {
        String[] mc = mobileCode.split(StrUtil.COLON);
        if (mc.length != 2) {
            return false;
        }

        String code = mc[0]; // 国家区号
        String mobile = mc[1]; // 手机号
        if (StrUtil.isBlank(code) || StrUtil.isBlank(mobile)) {
            return false;
        }

        if (!mobile.matches("^[0-9]*$") || !code.matches("^[0-9]*$")) {
            // 纯数字校验
            return false;
        }

        // 字典中获取验证规则
        String rule = null;
        try {
            List<DictDataRespDTO> dtos = DictFrameworkUtils.listDictDatasFromCache("phone_number_rule");
            if (CollUtil.isNotEmpty(dtos)) {
                DictDataRespDTO dto = dtos.stream().filter(d -> d.getValue().trim().equals(code.trim())).findFirst().orElseGet(null);
                if (Objects.nonNull(dto)) {
                    // 优先获取中文
                    rule = dto.getLabel();
                    if (StrUtil.isBlank(rule)) {
                        // 中文不存在，再获取英文
                        rule = dto.getLabelEn();
                    }
                }
            }
        }
        catch (Exception e) {
            log.error(String.format("获取手机号规则失败, code: %s, mobile: %s->", code, mobile), e);
        }

        if (StrUtil.isNotBlank(rule)) {
            log.info(String.format("获取手机号规则成功, code: %s, mobile: %s, rule: %s", code, mobile, rule));
            return mobile.matches(rule);
        }

        // 通用验证
        return checkPhoneNumber(mobile, code);

        /*switch (code) {
            case "86":
                // 中国
                if (!mobile.matches("1[23456789]\\d{9}")
                        || StrUtil.length(mobile) != 11) {
                    return false;
                }
                break;
            case "225":
                // 科特迪瓦
                if (StrUtil.length(mobile) != 10 && StrUtil.length(mobile) != 8) {
                    // 电话号码不能大于11位
                    return false;
                }
                break;
            case "233":
                // 加纳
                if ((StrUtil.length(mobile) != 10 && StrUtil.length(mobile) != 9) || mobile.startsWith("0")) {
                    // 电话号码9位或10位，且首字母不能为0
                    return false;
                }
                break;
            default:
                if(mobile.startsWith("0")){
                    //只有科特迪瓦可以0开头，其他国家不能0开头
                    return false;
                }
                return checkPhoneNumber(mobile, code);
        }
        return true;*/
    }


    @Data
    @Accessors(chain = true)
    public static class Area {
        private String province;
        private String city;
    }


    public static void main(String[] args) throws NumberParseException {
        PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
//        String phone = "234:8035875722";
//        System.out.println(phone+">>>>"+isMobileCode(phone));
//        String phone3 = "234:08035875722";
//        System.out.println(phone+">>>>"+isMobileCode(phone3));


//        String phone1="+2580856170352";
//        PhoneNumber numberProto = phoneUtil.parse(phone1, "");
//        String formattedNumber = phoneUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
//        System.out.println(phone1+"Formatted number: " + formattedNumber);
//        String number = PhoneNumberUtil.normalizeDigitsOnly(formattedNumber);
//        System.out.println(phone1+"Formatted number: " + number);


        String phone2="+23408035875722";
        String regionCode = phoneUtil.getRegionCodeForCountryCode(234);
        System.out.println("regionCode:"+ regionCode);
        PhoneNumber numberProto2 = phoneUtil.parse(phone2, regionCode);
        String formattedNumber2 = phoneUtil.format(numberProto2,PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
        System.out.println(phone2+" Formatted number2: " + formattedNumber2);
        String number2 = PhoneNumberUtil.normalizeDiallableCharsOnly(phone2);
        System.out.println(phone2+" Formatted number2: " + number2);
        System.out.println("15219293930".matches("1[23456789]\\d{9}"));


//
//        System.out.println("formatPhone1 234:8035875722>>>>"+PhoneUtil.formatPhone("234:8035875722"));;
//        System.out.println("formatPhone2 234:08035875722>>>>"+PhoneUtil.formatPhone("234:08035875722"));;
//
//        System.out.println("formatPhone3 86:020-82788546>>>>"+PhoneUtil.formatPhone("86:020-82788546"));;
//        System.out.println("formatPhone4 86:02082788546>>>>"+PhoneUtil.formatPhone("86:02082788546"));;
//        System.out.println("formatPhone5 86:2182788546>>>>"+PhoneUtil.formatPhone("86:2182788546"));;
//
//        System.out.println("formatPhone6 233:244739790>>>>"+PhoneUtil.formatPhone("233:244739790"));;
//        System.out.println("formatPhone7 233:0244739790>>>>"+PhoneUtil.formatPhone("233:0244739790"));;
//
//        System.out.println("formatPhone8 258:874785203>>>>"+PhoneUtil.formatPhone("258:874785203"));;
//        System.out.println("formatPhone9 258:0874785203>>>>"+PhoneUtil.formatPhone("258:0874785203"));;
//
//        System.out.println("formatPhone10 225:506183539>>>>"+PhoneUtil.formatPhone("225:506183539"));;
//        System.out.println("formatPhone11 225:0506183539>>>>"+PhoneUtil.formatPhone("225:0506183539"));;
//
//        System.out.println("formatPhone12 225:709254229>>>>"+PhoneUtil.formatPhone("225:709254229"));;
//        System.out.println("formatPhone13 225:0709254229>>>>"+PhoneUtil.formatPhone("225:0709254229"));;
//
//        System.out.println("formatPhone14 254:748847198>>>>"+PhoneUtil.formatPhone("254:748847198"));;
//        System.out.println("formatPhone15 254:0748847198>>>>"+PhoneUtil.formatPhone("225:0748847198"));;
//
//        System.out.println("formatPhone14 971:551017862>>>>"+PhoneUtil.formatPhone("971:551017862"));;
//        System.out.println("formatPhone15 971:0551017862>>>>"+PhoneUtil.formatPhone("971:0551017862"));;

//        System.out.println("formatPhone16 1:3038477362>>>>"+PhoneUtil.formatPhone("1:3038477362"));;
//        System.out.println("formatPhone17 1:03038477362>>>>"+PhoneUtil.formatPhone("1:03038477362"));;

    }
}
