
/**
 * 需要解析的地址，type是解析的方式，默认是正则匹配
 * @param address
 * @param options：type： 0:正则，1：树查找, textFilter： 清洗的字段
 * @returns {{}|({area: Array, province: Array, phone: string, city: Array, name: string, detail: Array} & {area: (*|string), province: (*|string), city: (*|string), detail: (Array|boolean|string|string)})}
 * @constructor
 */
const AddressParse = (address, options, provinceString, cityString, areaString) => {
    const { type = 0, textFilter = [] } = typeof options === 'object' ? options : {};

    if (!address) {
        return {}
    }

    const parseResult = {
        phone: '',
        province: [],
        city: [],
        area: [],
        detail: [],
        name: '',
    };
    address = cleanAddress(address, textFilter);

    // 识别手机号
    const resultPhone = filterPhone(address);
    address = resultPhone.address;
    parseResult.phone = resultPhone.phone;

    const resultCode = filterPostalCode(address);
    address = resultCode.address;
    parseResult.postalCode = resultCode.postalCode;

    // 地址分割
    const splitAddress = address.split(' ').filter(item => item).map(item => item.trim());

    // 找省市区和详细地址
    splitAddress.forEach((item) => {
        // 识别地址
        if (!parseResult.province[0] || !parseResult.city[0] || !parseResult.area[0]) {
            // 两个方法都可以解析，正则和树查找
            let parse;
            type === 1 && (parse = parseRegion(item, parseResult));
            type === 0 && (parse = parseRegionWithRegexp(item, parseResult, provinceString, cityString, areaString));
            const {province, city, area, detail} = parse;
            parseResult.province = province || [];
            parseResult.area = area || [];
            parseResult.city = city || [];
            parseResult.detail = parseResult.detail.concat(detail || []);
        } else {
            parseResult.detail.push(item);
        }
    });

    // 地址都解析完了，如果还没有姓名，那么姓名应该是在详细地址里面，取详细地址里面长度最小的那个
    if (!parseResult.name) {
        const detail = JSON.parse(JSON.stringify(parseResult.detail));
        detail.sort((a, b) => a.length - b.length);
        // console.log(judgeFragmentIsName(detail[0]));
        parseResult.name = detail[0];
        const nameIndex = parseResult.detail.findIndex(item => item === parseResult.name);
        parseResult.detail.splice(nameIndex, 1)
    }

    // log(JSON.stringify(parseResult));

    const province = parseResult.province[0];
    const city = parseResult.city[0];
    const area = parseResult.area[0];
    const detail = parseResult.detail;

    return Object.assign(parseResult, {
        province: (province && province.name) || '',
        city: (city && city.name) || '',
        area: (area && area.name) || '',
        detail: (detail && detail.length > 0 && detail.join('')) || ''
    })
};

/**
 * 利用正则表达式解析
 * @param fragment
 * @param hasParseResult
 * @returns {{area: (Array|*|string), province: (Array|*|string), city: (Array|*|string|string), detail: (*|Array)}}
 */
const parseRegionWithRegexp = (fragment, hasParseResult, provinceString, cityString, areaString) => {
    // log('----- 当前使用正则匹配模式 -----')
    let province = hasParseResult.province || [], city = hasParseResult.city || [], area = hasParseResult.area || [],
        detail = [];

    let matchStr = '';
    if (province.length === 0) {
        for (let i = 1; i < fragment.length; i++) {
            const str = fragment.substring(0, i + 1);
            const regexProvince = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\"}`, 'g');
            const matchProvince = provinceString.match(regexProvince);
            if (matchProvince) {
                const provinceObj = JSON.parse(matchProvince[0]);
                if (matchProvince.length === 1) {
                    province = [];
                    matchStr = str;
                    province.push(provinceObj)
                }
            } else {
                break
            }
        }

        if (province[0]) {
            fragment = fragment.replace(matchStr, '')
        }

    }

    if (city.length === 0) {
        for (let i = 1; i < fragment.length; i++) {
            const str = fragment.substring(0, i + 1);
            const regexCity = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\",\"provinceCode\":\"${province[0] ? `${province[0].code}` : '[0-9]{1,6}'}\"\}`, 'g');
            const matchCity = cityString.match(regexCity);
            if (matchCity) {
                const cityObj = JSON.parse(matchCity[0]);
                if (matchCity.length === 1) {
                    city = [];
                    matchStr = str;
                    city.push(cityObj);
                }
            } else {
                break;
            }
        }
        if (city[0]) {
            const {provinceCode} = city[0];
            fragment = fragment.replace(matchStr, '');
            if (province.length === 0) {
                const regexProvince = new RegExp(`\{\"code\":\"${provinceCode}\",\"name\":\"[\u4E00-\u9FA5]+?\"}`, 'g');
                const matchProvince = provinceString.match(regexProvince);
                province.push(JSON.parse(matchProvince[0]))
            }
        }

    }

    if (area.length === 0) {
        for (let i = 1; i < fragment.length; i++) {
            const str = fragment.substring(0, i + 1);
            const regexArea = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\",\"cityCode\":\"${city[0] ? city[0].code : '[0-9]{1,6}'}\",\"provinceCode\":\"${province[0] ? `${province[0].code}` : '[0-9]{1,6}'}\"\}`, 'g');
            const matchArea = areaString.match(regexArea);
            if (matchArea) {
                const areaObj = JSON.parse(matchArea[0]);
                if (matchArea.length === 1) {
                    area = [];
                    matchStr = str;
                    area.push(areaObj);
                }
            } else {
                break
            }
        }
        if (area[0]) {
            const {provinceCode, cityCode} = area[0];
            fragment = fragment.replace(matchStr, '');
            if (province.length === 0) {
                const regexProvince = new RegExp(`\{\"code\":\"${provinceCode}\",\"name\":\"[\u4E00-\u9FA5]+?\"}`, 'g');
                const matchProvince = provinceString.match(regexProvince);
                province.push(JSON.parse(matchProvince[0]));
            }
            if (city.length === 0) {
                const regexCity = new RegExp(`\{\"code\":\"${cityCode}\",\"name\":\"[\u4E00-\u9FA5]+?\",\"provinceCode\":\"${provinceCode}\"\}`, 'g');
                const matchCity = cityString.match(regexCity);
                city.push(JSON.parse(matchCity[0]));
            }
        }
    }


    // 解析完省市区如果还存在地址，则默认为详细地址
    if (fragment.length > 0) {
        detail.push(fragment)
    }

    return {
        province,
        city,
        area,
        detail,
    }
};

/**
 * 利用树向下查找解析
 * @param fragment
 * @param hasParseResult
 * @returns {{area: Array, province: Array, city: Array, detail: Array}}
 */
const parseRegion = (fragment, hasParseResult) => {
    // log('----- 当前使用树查找模式 -----')
    let province = [], city = [], area = [], detail = [];

    if (hasParseResult.province[0]) {
        province = hasParseResult.province
    } else {
        // 从省开始查找
        for (const tempProvince of provinces) {
            const {name} = tempProvince;
            let replaceName = '';
            for (let i = name.length; i > 1; i--) {
                const temp = name.substring(0, i);
                if (fragment.indexOf(temp) === 0) {
                    replaceName = temp;
                    break;
                }
            }
            if (replaceName) {
                province.push(tempProvince);
                fragment = fragment.replace(replaceName, '');
                break
            }
        }
    }
    if (hasParseResult.city[0]) {
        city = hasParseResult.city
    } else {
        // 从市区开始查找
        for (const tempCity of cities) {
            const {name, provinceCode} = tempCity;
            const currentProvince = province[0];
            // 有省
            if (currentProvince) {
                if (currentProvince.code === provinceCode) {
                    let replaceName = '';
                    for (let i = name.length; i > 1; i--) {
                        const temp = name.substring(0, i);
                        if (fragment.indexOf(temp) === 0) {
                            replaceName = temp;
                            break;
                        }
                    }
                    if (replaceName) {
                        city.push(tempCity);
                        fragment = fragment.replace(replaceName, '');
                        break;
                    }
                }
            } else {
                // 没有省，市不可能重名
                for (let i = name.length; i > 1; i--) {
                    const replaceName = name.substring(0, i);
                    if (fragment.indexOf(replaceName) === 0) {
                        city.push(tempCity);
                        province.push(provinces.find(item => item.code === provinceCode));
                        fragment = fragment.replace(replaceName, '');
                        break;
                    }
                }
                if (city.length > 0) {
                    break;
                }
            }
        }
    }

    // 从区市县开始查找
    for (const tempArea of areas) {
        const {name, provinceCode, cityCode} = tempArea;
        const currentProvince = province[0];
        const currentCity = city[0];

        // 有省或者市
        if (currentProvince || currentCity) {
            if ((currentProvince && currentProvince.code === provinceCode)
                || (currentCity && currentCity.code) === cityCode) {
                let replaceName = '';
                for (let i = name.length; i > 1; i--) {
                    const temp = name.substring(0, i);
                    if (fragment.indexOf(temp) === 0) {
                        replaceName = temp;
                        break
                    }
                }
                if (replaceName) {
                    area.push(tempArea);
                    !currentCity && city.push(cities.find(item => item.code === cityCode));
                    !currentProvince && province.push(provinces.find(item => item.code === provinceCode));
                    fragment = fragment.replace(replaceName, '');
                    break;
                }
            }
        } else {
            // 没有省市，区县市有可能重名，这里暂时不处理，因为概率极低，可以根据添加市解决
            for (let i = name.length; i > 1; i--) {
                const replaceName = name.substring(0, i);
                if (fragment.indexOf(replaceName) === 0) {
                    area.push(tempArea);
                    city.push(cities.find(item => item.code === cityCode));
                    province.push(provinces.find(item => item.code === provinceCode));
                    fragment = fragment.replace(replaceName, '');
                    break;
                }
            }
            if (area.length > 0) {
                break;
            }
        }
    }

    // 解析完省市区如果还存在地址，则默认为详细地址
    if (fragment.length > 0) {
        detail.push(fragment)
    }

    return {
        province,
        city,
        area,
        detail,
    }
};

/**
 * 匹配电话
 * @param address
 * @returns {{address: *, phone: string}}
 */
const filterPhone = (address) => {
    let phone = '';
    // 整理电话格式
    address = address.replace(/(\d{3})-(\d{4})-(\d{4})/g, '$1$2$3');
    address = address.replace(/(\d{3}) (\d{4}) (\d{4})/g, '$1$2$3');
    address = address.replace(/(\d{4}) \d{4} \d{4}/g, '$1$2$3');
    address = address.replace(/(\d{4})/g, '$1');

    const mobileReg = /(\d{7,12})|(\d{3,4}-\d{6,8})|(86-[1][0-9]{10})|(86[1][0-9]{10})|([1][0-9]{10})/g;
    const mobile = mobileReg.exec(address);
    if (mobile) {
        phone = mobile[0];
        address = address.replace(mobile[0], ' ')
    }
    return {address, phone}
};

/**
 * 匹配邮编
 * @param address
 * @returns {{address: *, postalCode: string}}
 */
const filterPostalCode = (address) => {
    let postalCode = '';
    const postalCodeReg = /\d{6}/g;
    const code = postalCodeReg.exec(address);
    if (code) {
        postalCode = code[0];
        address = address.replace(code[0], ' ');
    }
    return {address, postalCode}
};

/**
 * 地址清洗
 * @param address
 * @returns {*}
 */
const cleanAddress = (address, textFilter = []) => {
    // 去换行等
    address = address
        .replace(/\r\n/g, ' ')
        .replace(/\n/g, ' ')
        .replace(/\t/g, ' ');

    // 自定义去除关键字，可自行添加
    const search = [
        '详细地址',
        '收货地址',
        '收件地址',
        '地址',
        '所在地区',
        '地区',
        '姓名',
        '收货人',
        '收件人',
        '联系人',
        '收',
        '邮编',
        '联系电话',
        '电话',
        '联系人手机号码',
        '手机号码',
        '手机号',
    ].concat(textFilter);
    search.forEach(str => {
        address = address.replace(new RegExp(str, 'g'), ' ')
    });

    const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\]\.<>/?~！@#￥……&*（）——|{}【】‘；：”“’。，、？]", 'g');
    address = address.replace(pattern, ' ');

    // 多个空格replace为一个
    address = address.replace(/ {2,}/g, ' ');

    return address
};

export default AddressParse;
