# -*- coding: utf-8 -*-
"""生成网点/人员坐标库 + 距离矩阵（8 人 x 182 网点）。
坐标来源：机构全名里的地名关键词 + 杭州街道/镇/地标已知坐标，精度约 1~3 km（市区）、3~8 km（县域）。
可在 geodb.json 里手工修正任意一条后重跑 make.py。"""
import io, json, math, re, sys, os

BUILD = os.path.dirname(os.path.abspath(__file__))
ORGS = os.path.join(BUILD, '_orgs.json')

# 关键词 -> (区/县, 补充地址, lat, lng)
P = {
    # ==== 核心 =====
    '钱新大楼': ('上城区', '钱江新城 富春路', 30.2440, 120.2120),
    '庆春大楼': ('上城区', '庆春路', 30.2560, 120.1800),
    '零售金融部卡部': ('上城区', '庆春路 总行大楼', 30.2570, 120.1780),
    '火车西站办公点': ('余杭区', '杭州西站 仓前', 30.3200, 119.9900),
    '制卡室': ('上城区', '庆春路', 30.2570, 120.1780),
    '安邦': ('滨江区', '江南大道', 30.2080, 120.2180),
    '省公积金驻点': ('上城区', '延安路 建银中心', 30.2600, 120.1680),
    '现金中心': ('上城区', '钱江新城', 30.2540, 120.2150),
    '金融大厦': ('上城区', '浣纱路', 30.2520, 120.1680),
    '客服': ('上城区', '庆春路', 30.2580, 120.1800),
    '临平数据中心': ('临平区', '临平', 30.4200, 120.3000),
    '建银中心': ('上城区', '延安路', 30.2600, 120.1680),
    '西湖区政府': ('西湖区', '文三路 区政府', 30.2700, 120.1300),
    '上城区区政府': ('上城区', '望江东路 区政府', 30.2400, 120.1800),
    '丁桥皋亭山': ('上城区', '丁桥 皋亭山', 30.3350, 120.2250),
    '临安行政中心': ('临安区', '锦城 行政中心', 30.2330, 119.7240),
    '市中医院': ('上城区', '环城西路 市中医院', 30.2640, 120.1660),
    '市总工会': ('上城区', '平海路 总工会', 30.2620, 120.1700),
    '西溪医院': ('西湖区', '留下 西溪医院', 30.2630, 120.0750),
    '西站': ('余杭区', '杭州西站', 30.3200, 119.9900),
    '滨江财政': ('滨江区', '江南大道', 30.2050, 120.2120),
    '市丁桥医院': ('上城区', '丁桥', 30.3320, 120.2220),
    '市公安局': ('上城区', '解放东路 市公安局', 30.2500, 120.2000),
    '三堡运新花苑': ('上城区', '三堡 运新花苑', 30.2530, 120.2450),
    '市财政局': ('上城区', '解放东路 市财政局', 30.2500, 120.1920),
    '市福利院': ('拱墅区', '大关 福利院', 30.3000, 120.1700),
    '公共资源交易中心': ('上城区', '钱江新城 市民中心', 30.2480, 120.2120),
    '市肿瘤医院': ('拱墅区', '半山 肿瘤医院', 30.3600, 120.1900),
    '市燃气集团': ('拱墅区', '环城北路', 30.2800, 120.1800),
    '钱塘春晓大厦': ('滨江区', '闻堰 钱塘春晓', 30.2200, 120.2100),
    '余杭二院': ('余杭区', '余杭街道 二院', 30.2670, 119.9760),
    '市公安办证大厅': ('上城区', '市民中心', 30.2480, 120.2100),
    '同德医院': ('余杭区', '闲林 同德医院', 30.2500, 120.0300),
    '桐庐桦桐家私': ('桐庐县', '桐庐经济开发区', 29.7970, 119.6880),
    '天阳D32': ('上城区', '丁桥 天阳D32', 30.3400, 120.2200),
    '老年病医院': ('拱墅区', '康桥 老年病医院', 30.2800, 120.1500),
    '大江东办事中心': ('钱塘区', '大江东 办事中心', 30.3200, 120.5000),
    '临安电子科大': ('临安区', '青山湖 电子科大', 30.2400, 119.8300),
    '红会医院': ('上城区', '环城东路 红会医院', 30.3000, 120.2000),
    '市委党校': ('西湖区', '转塘 市委党校', 30.3000, 120.1000),
    '半山自助': ('拱墅区', '半山', 30.3550, 120.1950),
    '新华医院': ('拱墅区', '上塘 新华医院', 30.2900, 120.1600),
    '绍兴科创大厦': ('绍兴市', '绍兴 科创大厦', 30.0300, 120.5800),
    '金融办': ('上城区', '钱江新城 金融办', 30.2500, 120.2100),
    # ==== 余杭/临平/萧山/富阳/临安/桐庐/建德/淳安 ====
    '青山湖支行': ('临安区', '青山湖', 30.2400, 119.8300),
    '青山湖科技城': ('临安区', '青山湖科技城', 30.2500, 119.8300),
    '银湖': ('富阳区', '银湖街道', 30.1000, 119.9800),
    '新登': ('富阳区', '新登镇', 29.9800, 119.7900),
    '江南商城': ('富阳区', '富阳 江南商城', 30.0400, 119.9500),
    '富阳': ('富阳区', '富春街道', 30.0500, 119.9600),
    '千岛湖': ('淳安县', '千岛湖镇', 29.6050, 119.0430),
    '淳安': ('淳安县', '千岛湖镇', 29.6050, 119.0430),
    '新安江': ('建德市', '新安江街道', 29.4760, 119.2810),
    '建德': ('建德市', '新安江街道', 29.4760, 119.2810),
    '分水': ('桐庐县', '分水镇', 29.9300, 119.5500),
    '桐庐': ('桐庐县', '桐君街道', 29.7970, 119.6880),
    '昌化': ('临安区', '昌化镇', 30.1700, 119.2200),
    '钱王': ('临安区', '钱王街 锦城', 30.2330, 119.7200),
    '临安': ('临安区', '锦城街道', 30.2330, 119.7240),
    '瓜沥': ('萧山区', '瓜沥镇', 30.1800, 120.4200),
    '临浦': ('萧山区', '临浦镇', 30.0500, 120.2500),
    '义桥': ('萧山区', '义桥镇', 30.0500, 120.2000),
    '南阳': ('萧山区', '南阳街道', 30.1500, 120.3000),
    '新街': ('萧山区', '新街街道', 30.1900, 120.3300),
    '宁围': ('萧山区', '宁围街道', 30.2200, 120.2800),
    '晨晖': ('萧山区', '北干 晨晖路', 30.1900, 120.3000),
    '钱江世纪城': ('萧山区', '钱江世纪城', 30.2300, 120.2500),
    '经济技术开发区': ('萧山区', '萧山经开区', 30.2100, 120.2800),
    '城厢': ('萧山区', '城厢街道', 30.1700, 120.2700),
    '萧山': ('萧山区', '北干街道', 30.1830, 120.2640),
    '塘栖': ('临平区', '塘栖镇', 30.4800, 120.1900),
    '崇贤': ('临平区', '崇贤街道', 30.4000, 120.1700),
    '乔司': ('临平区', '乔司街道', 30.3600, 120.2800),
    '临平经济开发区': ('临平区', '临平经开区', 30.4000, 120.3200),
    '临平': ('临平区', '临平街道', 30.4200, 120.3000),
    '瓶窑': ('余杭区', '瓶窑镇', 30.4200, 119.9400),
    '良渚': ('余杭区', '良渚街道', 30.3800, 120.0000),
    '勾庄': ('余杭区', '勾庄 农副物流', 30.3500, 120.0300),
    '仁和': ('余杭区', '仁和街道', 30.4200, 120.0900),
    '闲林': ('余杭区', '闲林街道', 30.2500, 120.0300),
    '五常': ('余杭区', '五常街道', 30.3000, 120.0300),
    '海创园': ('余杭区', '未来科技城 海创园', 30.2800, 120.0000),
    '宝塔': ('余杭区', '余杭街道 宝塔', 30.2600, 119.9700),
    '余杭': ('余杭区', '余杭街道', 30.2700, 119.9800),
    '大江东': ('钱塘区', '大江东', 30.3200, 120.5000),
    '江东大道': ('钱塘区', '江东大道', 30.3000, 120.4500),
    '金沙': ('钱塘区', '下沙 金沙湖', 30.3100, 120.3300),
    '上沙': ('钱塘区', '下沙 上沙', 30.3000, 120.3300),
    '下沙开发区': ('钱塘区', '下沙 开发区', 30.3000, 120.3400),
    '钱塘智慧城': ('上城区', '九堡 钱塘智慧城', 30.3100, 120.2800),
    '钱塘': ('钱塘区', '下沙', 30.3000, 120.3600),
    # ==== 主城区 ====
    '三墩厚仁路': ('西湖区', '三墩镇 厚仁路', 30.3240, 120.0890),
    '三墩': ('西湖区', '三墩镇', 30.3200, 120.0900),
    '丁桥大唐苑': ('上城区', '丁桥 大唐苑', 30.3350, 120.2250),
    '丁桥': ('上城区', '丁桥', 30.3300, 120.2200),
    '双浦': ('西湖区', '双浦镇', 30.1400, 120.1000),
    '米市巷': ('拱墅区', '米市巷', 30.2770, 120.1630),
    '文新金乐': ('西湖区', '文新 金乐', 30.2880, 120.0950),
    '西兴西陵': ('滨江区', '西兴 西陵', 30.1900, 120.2150),
    '潮鸣艮园': ('拱墅区', '潮鸣 艮园', 30.2670, 120.1730),
    '采荷红菱': ('上城区', '采荷 红菱', 30.2470, 120.1960),
    '滨江文化中心': ('滨江区', '滨江 文化中心', 30.2080, 120.2080),
    '浣纱': ('上城区', '浣纱路', 30.2520, 120.1680),
    '平海': ('上城区', '平海路', 30.2580, 120.1680),
    '之江度假区': ('西湖区', '之江度假区', 30.1800, 120.1200),
    '之江': ('西湖区', '之江路', 30.1900, 120.1300),
    '涌金': ('上城区', '涌金门', 30.2470, 120.1630),
    '南山': ('上城区', '南山路', 30.2320, 120.1520),
    '江城': ('上城区', '江城路', 30.2400, 120.1900),
    '城站': ('上城区', '城站火车站', 30.2430, 120.1800),
    '闸口': ('上城区', '闸口 复兴', 30.2000, 120.1600),
    '秋涛': ('上城区', '秋涛路', 30.2550, 120.2000),
    '四季青': ('上城区', '四季青 服装市场', 30.2500, 120.2100),
    '天城路': ('上城区', '天城路', 30.2900, 120.2100),
    '笕桥': ('上城区', '笕桥街道', 30.3200, 120.2300),
    '彭埠': ('上城区', '彭埠街道', 30.2900, 120.2200),
    '八堡': ('上城区', '九堡 八堡', 30.3200, 120.3000),
    '魅力城': ('上城区', '九堡 魅力城', 30.3200, 120.2800),
    '九堡': ('上城区', '九堡街道', 30.3100, 120.2900),
    '望江大通桥': ('上城区', '望江 大通桥', 30.2300, 120.1900),
    '望江': ('上城区', '望江街道', 30.2350, 120.1850),
    '清波': ('上城区', '清波门', 30.2400, 120.1600),
    '官巷口': ('上城区', '官巷口', 30.2500, 120.1700),
    '复兴': ('上城区', '复兴路', 30.2100, 120.1600),
    '新塘路': ('上城区', '新塘路', 30.2600, 120.2000),
    '夕照': ('上城区', '夕照寺 江干', 30.2200, 120.1800),
    '市民中心': ('上城区', '钱江新城 市民中心', 30.2450, 120.2150),
    '清泰': ('上城区', '清泰街', 30.2400, 120.1900),
    '庆春': ('上城区', '庆春路', 30.2600, 120.1800),
    '武林门': ('拱墅区', '武林门', 30.2700, 120.1600),
    '湖墅': ('拱墅区', '湖墅南路', 30.2930, 120.1530),
    '德胜': ('拱墅区', '德胜路', 30.3050, 120.1660),
    '大关': ('拱墅区', '大关路', 30.3100, 120.1600),
    '丰潭': ('西湖区', '丰潭路', 30.2900, 120.1150),
    '拱宸桥': ('拱墅区', '拱宸桥', 30.3180, 120.1430),
    '城北': ('拱墅区', '城北 拱墅', 30.3200, 120.1500),
    '汽车城': ('拱墅区', '石祥路 汽车城', 30.3300, 120.1600),
    '莫干山路': ('拱墅区', '莫干山路', 30.3100, 120.1400),
    '香积寺路': ('拱墅区', '香积寺路', 30.3100, 120.1700),
    '上塘智慧网谷': ('拱墅区', '上塘 智慧网谷', 30.3500, 120.1600),
    '电厂': ('拱墅区', '半山 电厂', 30.3500, 120.1900),
    '东新': ('拱墅区', '东新路', 30.3150, 120.1750),
    '春晖': ('拱墅区', '春晖路', 30.3000, 120.1800),
    '艮山': ('拱墅区', '艮山门', 30.2900, 120.1900),
    '环北': ('拱墅区', '环城北路', 30.2800, 120.1700),
    '天水': ('拱墅区', '天水街道', 30.2700, 120.1700),
    '朝晖': ('拱墅区', '朝晖街道', 30.2900, 120.1700),
    '建国路': ('拱墅区', '建国北路', 30.2800, 120.1850),
    '石桥': ('拱墅区', '石桥街道', 30.3430, 120.1960),
    '延中大楼': ('上城区', '延安路 延中大楼', 30.2600, 120.1660),
    '华成': ('拱墅区', '湖墅南路 华成', 30.2800, 120.1600),
    '西湖': ('西湖区', '西湖 湖滨', 30.2600, 120.1500),
    '学院路': ('西湖区', '学院路', 30.2800, 120.1300),
    '西溪': ('西湖区', '西溪', 30.2800, 120.0900),
    '保俶': ('西湖区', '保俶路', 30.2700, 120.1500),
    '北山': ('西湖区', '北山街', 30.2600, 120.1400),
    '高新': ('滨江区', '滨江 高新', 30.1900, 120.2100),
    '文创': ('西湖区', '之江 文创园', 30.1900, 120.1000),
    '求是': ('西湖区', '求是路', 30.2700, 120.1300),
    '西城': ('西湖区', '西城 蒋村', 30.3000, 120.1000),
    '城西': ('西湖区', '古墩路 城西', 30.2900, 120.1100),
    '留下': ('西湖区', '留下街道', 30.2700, 120.0500),
    '蒋村': ('西湖区', '蒋村街道', 30.2800, 120.0700),
    '紫金港': ('西湖区', '紫金港', 30.3000, 120.0900),
    '云荷廷': ('西湖区', '云荷廷 三墩', 30.2500, 120.1000),
    '五幸': ('西湖区', '五幸 三墩', 30.3100, 120.1000),
    '茅家埠': ('西湖区', '西湖 茅家埠', 30.2400, 120.1300),
    '滨江': ('滨江区', '滨江 江南大道', 30.2080, 120.2100),
    '钱江': ('滨江区', '滨江 钱江', 30.2000, 120.2200),
    '西兴': ('滨江区', '西兴街道', 30.1900, 120.2100),
    '浦沿': ('滨江区', '浦沿街道', 30.1900, 120.1600),
    '长河': ('滨江区', '长河街道', 30.1800, 120.2000),
    '白马湖': ('滨江区', '白马湖', 30.1700, 120.1800),
    '江南': ('滨江区', '江南大道', 30.2100, 120.2100),
    '科技': ('滨江区', '滨江 科技园', 30.1900, 120.2000),
    '城东': ('上城区', '秋涛北路 城东', 30.2700, 120.2100),
    '金龙财富大厦': ('上城区', '钱江新城 金龙财富大厦', 30.2400, 120.2100),
    '小微信贷中心': ('上城区', '庆春路 小微信贷中心', 30.2550, 120.1900),
    '信用小微事业部杭州中心': ('上城区', '钱江新城 金龙财富大厦', 30.2400, 120.2100),
    '总行营业部': ('上城区', '庆春路 总行营业部', 30.2570, 120.1750),
    '上海普陀': ('上海市', '普陀区', 31.2500, 121.3900),
}

DISTRICT_CENTER = {
    '上城区': (30.2500, 120.1900), '拱墅区': (30.2900, 120.1600), '西湖区': (30.2700, 120.1200),
    '滨江区': (30.2000, 120.2050), '萧山区': (30.1830, 120.2640), '余杭区': (30.2700, 119.9800),
    '临平区': (30.4200, 120.3000), '钱塘区': (30.3100, 120.3400), '富阳区': (30.0500, 119.9600),
    '临安区': (30.2330, 119.7240), '桐庐县': (29.7970, 119.6880), '建德市': (29.4760, 119.2810),
    '淳安县': (29.6050, 119.0430), '绍兴市': (30.0300, 120.5800), '上海市': (31.2500, 121.3900),
}

# 坐标来源标记：osm = OpenStreetMap/photon 实测；est = 手工估算（OSM 查不到该小区）
HOMES = {
    '崇盛里': ('拱墅区', '拱宸桥街道 崇盛里', 30.325953, 120.140395, 'osm'),
    '风来旭和府': ('临平区', '乔司街道 风来旭和府', 30.3560, 120.2820, 'est'),
    '如玺华院': ('临平区', '乔司街道 如玺华院', 30.3520, 120.2780, 'est'),
    '桦枫居': ('拱墅区', '石桥街道 杭玻街 桦枫居', 30.345511, 120.190124, 'osm'),
    '盛世钱塘': ('上城区', '钱江路 盛世钱塘', 30.262534, 120.216748, 'osm'),
    '吉鸿家园': ('西湖区', '三墩镇 周坪路 吉鸿家园', 30.346533, 120.065691, 'osm'),
    '海上海': ('余杭区', '良渚街道 海上海', 30.348581, 120.074716, 'osm'),
    '慧仁家园': ('西湖区', '三墩镇 荡鱼街 慧仁家园', 30.333747, 120.072283, 'osm'),
    '圣苑': ('西湖区', '圣苑 西湖区', 30.2600, 120.1300, 'est'),
    '水韵康桥康泽苑': ('拱墅区', '康桥街道 康桥路 水韵康桥康盛苑', 30.371409, 120.131004, 'osm'),
}

KEYS = sorted(P.keys(), key=len, reverse=True)


def locate(name):
    for k in KEYS:
        if k in name:
            return k, P[k]
    return None, None


def hav(lat1, lng1, lat2, lng2):
    R = 6371.0
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp = p2 - p1
    dl = math.radians(lng2 - lng1)
    a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
    return round(2 * R * math.asin(math.sqrt(a)), 1)


def area_centers(orgs):
    acc = {}
    for o in orgs:
        if not o['lat']:
            continue
        a = o.get('r2') or ''
        s = acc.setdefault(a, [0.0, 0.0, 0])
        s[0] += o['lat']; s[1] += o['lng']; s[2] += 1
    out = {}
    for a, s in acc.items():
        if s[2]:
            out[a] = [round(s[0] / s[2], 4), round(s[1] / s[2], 4)]
    return out


def main():
    orgs = json.load(io.open(ORGS, encoding='utf-8'))
    out_orgs = []
    miss = []
    for o in orgs:
        k, v = locate(o['n'])
        if v is None:
            miss.append(o['n'])
            out_orgs.append({'c': o['c'], 'n': o['n'], 'a': '', 'lat': 0, 'lng': 0, 'src': 'none'})
            continue
        dist, addr, lat, lng = v
        out_orgs.append({
            'c': o['c'], 'n': o['n'], 'r2': o['r2'],
            'a': ('%s%s' % (dist, addr)).replace('市区', ''),
            'lat': lat, 'lng': lng, 'src': 'guess:' + k,
        })
    homes = []
    for nm, v in HOMES.items():
        homes.append({'n': nm, 'a': v[0] + v[1], 'lat': v[2], 'lng': v[3],
                      'src': v[4] if len(v) > 4 else 'est'})
    dist = {}
    for h in homes:
        d = {}
        for o in out_orgs:
            if not o['lat']:
                continue
            d[o['c']] = hav(h['lat'], h['lng'], o['lat'], o['lng'])
        dist[h['n']] = d
    db = {'orgs': out_orgs, 'homes': homes, 'dist': dist,
          'areaCenters': area_centers(out_orgs),
          'note': '坐标为按网点名称关键词估算的中心点，精度约 1~3 km（市区）/3~8 km（县域）；可手工修正'}
    p = os.path.join(BUILD, 'geodb.json')
    io.open(p, 'w', encoding='utf-8').write(json.dumps(db, ensure_ascii=False, separators=(',', ':')))
    print('orgs=%d located=%d miss=%d homes=%d distPairs=%d' % (
        len(out_orgs), sum(1 for x in out_orgs if x['lat']), len(miss), len(homes),
        sum(len(v) for v in dist.values())))
    if miss:
        print('MISS:', ' / '.join(miss))
    print('size=%.1fKB' % (os.path.getsize(p) / 1024.0))


if __name__ == '__main__':
    main()
