package service

import (
	"strconv"
	"strings"
)

// countryZh ISO2 → 中文国名（展示用；存储仍用 ISO）
var countryZh = map[string]string{
	"CN": "中国", "HK": "中国香港", "MO": "中国澳门", "TW": "中国台湾",
	"US": "美国", "JP": "日本", "KR": "韩国", "SG": "新加坡",
	"GB": "英国", "DE": "德国", "FR": "法国", "RU": "俄罗斯",
	"CA": "加拿大", "AU": "澳大利亚", "IN": "印度", "TH": "泰国",
	"VN": "越南", "MY": "马来西亚", "ID": "印度尼西亚", "PH": "菲律宾",
	"NL": "荷兰", "IT": "意大利", "ES": "西班牙", "BR": "巴西",
	"MX": "墨西哥", "SE": "瑞典", "CH": "瑞士", "PL": "波兰",
	"TR": "土耳其", "SA": "沙特阿拉伯", "AE": "阿联酋", "NZ": "新西兰",
	"IE": "爱尔兰", "BE": "比利时", "AT": "奥地利", "NO": "挪威",
	"DK": "丹麦", "FI": "芬兰", "PT": "葡萄牙", "CZ": "捷克",
	"UA": "乌克兰", "IL": "以色列", "ZA": "南非", "AR": "阿根廷",
}

type cnRegionMeta struct {
	Name string
	ISO  string
}

// cnRegionMap 中国省级英文名/别名 → 中文名 + 地图 ISO
var cnRegionMap = map[string]cnRegionMeta{
	"beijing":          {Name: "北京", ISO: "BJ"},
	"peking":           {Name: "北京", ISO: "BJ"},
	"tianjin":          {Name: "天津", ISO: "TJ"},
	"shanghai":         {Name: "上海", ISO: "SH"},
	"chongqing":        {Name: "重庆", ISO: "CQ"},
	"chungking":        {Name: "重庆", ISO: "CQ"},
	"hebei":            {Name: "河北", ISO: "HE"},
	"shanxi":           {Name: "山西", ISO: "SX"},
	"liaoning":         {Name: "辽宁", ISO: "LN"},
	"jilin":            {Name: "吉林", ISO: "JL"},
	"heilongjiang":     {Name: "黑龙江", ISO: "HL"},
	"jiangsu":          {Name: "江苏", ISO: "JS"},
	"zhejiang":         {Name: "浙江", ISO: "ZJ"},
	"anhui":            {Name: "安徽", ISO: "AH"},
	"fujian":           {Name: "福建", ISO: "FJ"},
	"jiangxi":          {Name: "江西", ISO: "JX"},
	"shandong":         {Name: "山东", ISO: "SD"},
	"henan":            {Name: "河南", ISO: "HA"},
	"hubei":            {Name: "湖北", ISO: "HB"},
	"hunan":            {Name: "湖南", ISO: "HN"},
	"guangdong":        {Name: "广东", ISO: "GD"},
	"guangxi":          {Name: "广西", ISO: "GX"},
	"hainan":           {Name: "海南", ISO: "HI"},
	"sichuan":          {Name: "四川", ISO: "SC"},
	"guizhou":          {Name: "贵州", ISO: "GZ"},
	"yunnan":           {Name: "云南", ISO: "YN"},
	"xizang":           {Name: "西藏", ISO: "XZ"},
	"tibet":            {Name: "西藏", ISO: "XZ"},
	"shaanxi":          {Name: "陕西", ISO: "SN"},
	"shaanxi province": {Name: "陕西", ISO: "SN"},
	"gansu":            {Name: "甘肃", ISO: "GS"},
	"qinghai":          {Name: "青海", ISO: "QH"},
	"ningxia":          {Name: "宁夏", ISO: "NX"},
	"xinjiang":         {Name: "新疆", ISO: "XJ"},
	"xinjiang uygur":   {Name: "新疆", ISO: "XJ"},
	"inner mongolia":   {Name: "内蒙古", ISO: "NM"},
	"nei mongol":       {Name: "内蒙古", ISO: "NM"},
	"guangxi zhuangzu": {Name: "广西", ISO: "GX"},
	"ningxia huizu":    {Name: "宁夏", ISO: "NX"},
	"hong kong":        {Name: "香港", ISO: "HK"},
	"macau":            {Name: "澳门", ISO: "MO"},
	"macao":            {Name: "澳门", ISO: "MO"},
	"taiwan":           {Name: "台湾", ISO: "TW"},
	// 台湾各县市（IP2Location 常直接给县市名作为 region）
	"changhua":   {Name: "台湾", ISO: "TW"},
	"chiayi":     {Name: "台湾", ISO: "TW"},
	"hsinchu":    {Name: "台湾", ISO: "TW"},
	"hualien":    {Name: "台湾", ISO: "TW"},
	"kaohsiung":  {Name: "台湾", ISO: "TW"},
	"keelung":    {Name: "台湾", ISO: "TW"},
	"kinmen":     {Name: "台湾", ISO: "TW"},
	"lienchiang": {Name: "台湾", ISO: "TW"},
	"miaoli":     {Name: "台湾", ISO: "TW"},
	"nantou":     {Name: "台湾", ISO: "TW"},
	"new taipei": {Name: "台湾", ISO: "TW"},
	"penghu":     {Name: "台湾", ISO: "TW"},
	"pingtung":   {Name: "台湾", ISO: "TW"},
	"taichung":   {Name: "台湾", ISO: "TW"},
	"tainan":     {Name: "台湾", ISO: "TW"},
	"taipei":     {Name: "台湾", ISO: "TW"},
	"taitung":    {Name: "台湾", ISO: "TW"},
	"taoyuan":    {Name: "台湾", ISO: "TW"},
	"yilan":      {Name: "台湾", ISO: "TW"},
	"yunlin":     {Name: "台湾", ISO: "TW"},
}

// cityZh 定义见 geo_zh_cities.go（LITE 中国城市全表 + 同音复合键）

// asnOrgZh 常见 ASN / AS 组织名 → 中文运营商
var asnOrgZh = map[uint]string{
	4134:  "中国电信",
	4812:  "中国电信",
	4837:  "中国联通",
	4808:  "中国联通",
	9808:  "中国移动",
	56040: "中国移动",
	56041: "中国移动",
	56042: "中国移动",
	4538:  "教育网",
	23910: "教育网",
	58539: "教育网",
	7497:  "教育网",
}

var asnOrgKeywordZh = []struct {
	kw string
	zh string
}{
	{"chinanet", "中国电信"},
	{"china telecom", "中国电信"},
	{"chinatelecom", "中国电信"},
	{"unicom", "中国联通"},
	{"china unicom", "中国联通"},
	{"mobile", "中国移动"},
	{"china mobile", "中国移动"},
	{"cernet", "教育网"},
	{"education", "教育网"},
}

// CountryLabelZh ISO2 → 中文国名（未知则返回原码）
func CountryLabelZh(iso string) string {
	iso = strings.ToUpper(strings.TrimSpace(iso))
	if iso == "" {
		return ""
	}
	if v, ok := countryZh[iso]; ok {
		return v
	}
	return iso
}

// ApplyGeoZh 就地补充中文省/市/运营商；country 保持 ISO2
func ApplyGeoZh(g *GeoInfo) {
	if g == nil {
		return
	}
	g.Country = normalizeCountryCode(g.Country)
	if g.Country == "CN" || g.Country == "HK" || g.Country == "MO" || g.Country == "TW" {
		mapCNRegionCity(g)
	}
	if g.ASN > 0 {
		if zh, ok := asnOrgZh[g.ASN]; ok {
			g.ASOrg = zh
		} else if g.ASOrg != "" {
			g.ASOrg = mapASOrgZh(g.ASOrg)
		}
	} else if g.ASOrg != "" {
		g.ASOrg = mapASOrgZh(g.ASOrg)
	}
	g.Region = truncateRunes(strings.TrimSpace(g.Region), 64)
	g.City = truncateRunes(strings.TrimSpace(g.City), 64)
	g.ASOrg = truncateRunes(strings.TrimSpace(g.ASOrg), 128)
}

func mapCNRegionCity(g *GeoInfo) {
	if g.RegionISO == "" {
		if meta, ok := lookupCNRegion(g.Region); ok {
			g.Region = meta.Name
			g.RegionISO = meta.ISO
		}
	} else if g.Region != "" {
		if meta, ok := lookupCNRegion(g.Region); ok {
			if g.RegionISO == "" {
				g.RegionISO = meta.ISO
			}
			g.Region = meta.Name
		}
	} else if g.RegionISO != "" {
		for _, meta := range cnRegionMap {
			if meta.ISO == strings.ToUpper(g.RegionISO) {
				g.Region = meta.Name
				break
			}
		}
	}
	if g.City != "" {
		if zh, ok := lookupCityZh(g.RegionISO, g.Region, g.City); ok {
			g.City = zh
		}
	}
	// 直辖市：BIN 有时只给城市不给省
	if g.Region == "" && g.City != "" {
		switch g.City {
		case "北京", "上海", "天津", "重庆":
			g.Region = g.City
			if meta, ok := cnRegionMap[strings.ToLower(g.City)]; ok {
				g.RegionISO = meta.ISO
			}
		}
	}
}

func lookupCNRegion(name string) (cnRegionMeta, bool) {
	key := strings.ToLower(strings.TrimSpace(name))
	if key == "" {
		return cnRegionMeta{}, false
	}
	if meta, ok := cnRegionMap[key]; ok {
		return meta, true
	}
	// 去掉常见后缀再试
	for _, suffix := range []string{" province", " sheng", " autonomous region", " municipality", " zhuangzu", " huizu", " uygur"} {
		if strings.HasSuffix(key, suffix) {
			if meta, ok := cnRegionMap[strings.TrimSuffix(key, suffix)]; ok {
				return meta, true
			}
		}
	}
	return cnRegionMeta{}, false
}

// lookupCityZh 将 IP2Location 英文城市名映射为中文。
// 同音城市优先用「省ISO|城市」复合键；并尝试去掉 city/shi 后缀与撇号变体。
func lookupCityZh(regionISO, region, name string) (string, bool) {
	key := normalizeCityKey(name)
	if key == "" {
		return "", false
	}
	iso := strings.ToLower(strings.TrimSpace(regionISO))
	if iso == "" {
		if meta, ok := lookupCNRegion(region); ok {
			iso = strings.ToLower(meta.ISO)
		}
	}
	candidates := cityKeyCandidates(key)
	if iso != "" {
		for _, c := range candidates {
			if zh, ok := cityZh[iso+"|"+c]; ok {
				return zh, true
			}
		}
	}
	for _, c := range candidates {
		if zh, ok := cityZh[c]; ok {
			return zh, true
		}
	}
	return "", false
}

func normalizeCityKey(name string) string {
	key := strings.ToLower(strings.TrimSpace(name))
	if key == "" || key == "-" {
		return ""
	}
	return key
}

func cityKeyCandidates(key string) []string {
	seen := map[string]struct{}{}
	var out []string
	add := func(s string) {
		s = strings.TrimSpace(s)
		if s == "" {
			return
		}
		if _, ok := seen[s]; ok {
			return
		}
		seen[s] = struct{}{}
		out = append(out, s)
	}
	add(key)
	add(strings.ReplaceAll(key, "'", ""))
	for _, suffix := range []string{" city", " shi"} {
		if strings.HasSuffix(key, suffix) {
			base := strings.TrimSuffix(key, suffix)
			add(base)
			add(strings.ReplaceAll(base, "'", ""))
		}
	}
	return out
}

func mapASOrgZh(org string) string {
	l := strings.ToLower(strings.TrimSpace(org))
	if l == "" {
		return org
	}
	for _, rule := range asnOrgKeywordZh {
		if strings.Contains(l, rule.kw) {
			return rule.zh
		}
	}
	// "AS4134 Chinanet" 等形式
	if strings.HasPrefix(l, "as") {
		num := strings.TrimPrefix(l, "as")
		if i := strings.IndexByte(num, ' '); i >= 0 {
			num = num[:i]
		}
		if n, err := strconv.ParseUint(num, 10, 32); err == nil {
			if zh, ok := asnOrgZh[uint(n)]; ok {
				return zh
			}
		}
	}
	return org
}
