package printer

import (
	"fmt"
	"strings"

	"github.com/xgadget-lab/nexttrace/trace"
)

type HopInfo int

const (
	General HopInfo = 0
	IXP     HopInfo = 1
	Peer    HopInfo = 2
	PoP     HopInfo = 3
	Aboard  HopInfo = 4
)

func findLatestAvailableHop(res *trace.Result, ttl int, probesIndex int) int {
	for ttl > 0 {
		// 查找上一个跃点是不是有效结果
		ttl--
		// 判断此TTL跃点是否有效并判断地理位置结构体是否已经初始化
		if len(res.Hops[ttl]) != 0 && res.Hops[ttl][probesIndex].Success && res.Hops[ttl][probesIndex].Geo != nil {
			// TTL虽有效，但地理位置API没有能够正确返回数据，依旧不能视为有效数据
			if res.Hops[ttl][probesIndex].Geo.Country == "" {
				// 跳过继续寻找上一个有效跃点
				continue
			}
			return ttl
		}
	}
	// 没找到
	return -1
}

func unifyName(name string) string {
	if name == "China" || name == "CN" {
		return "中国"
	} else if name == "Hong kong" || name == "香港" || name == "Central and Western" {
		return "中国香港"
	} else if name == "Taiwan" || name == "台湾" {
		return "中国台湾"
	} else {
		return name
	}
}

func chinaISPPeer(hostname string) bool {
	var keyWords = []string{"china", "ct", "cu", "cm", "cnc", "4134", "4837", "4809", "9929"}
	for _, k := range keyWords {
		if strings.Contains(strings.ToLower(hostname), k) {
			return true
		}
	}
	return false
}

func chinaMainland(h trace.Hop) bool {
	if unifyName(h.Geo.Country) == "中国" && unifyName(h.Geo.Prov) != "中国香港" && unifyName(h.Geo.Prov) != "中国台湾" {
		return true
	} else {
		return false
	}
}

func makeHopsType(res *trace.Result, ttl int) map[int]HopInfo {
	// 创建一个字典，存放所有当前TTL的跃点类型集合
	hopProbesMap := make(map[int]HopInfo)
	for i := range res.Hops[ttl] {
		// 判断是否res.Hops[ttl][i]是一个有效的跃点并且地理位置信息已经初始化
		if res.Hops[ttl][i].Success && res.Hops[ttl][i].Geo != nil {
			if availableTTL := findLatestAvailableHop(res, ttl, i); availableTTL != -1 {
				switch {
				case strings.Contains(res.Hops[ttl][i].Geo.District, "IXP") || strings.Contains(strings.ToLower(res.Hops[ttl][i].Hostname), "ix"):
					hopProbesMap[i] = IXP
				case strings.Contains(res.Hops[ttl][i].Geo.District, "Peer") || chinaISPPeer(res.Hops[ttl][i].Hostname):
					hopProbesMap[i] = Peer
				case strings.Contains(res.Hops[ttl][i].Geo.District, "PoP"):
					hopProbesMap[i] = PoP
				// 2个有效跃点必须都为有效数据，如果当前跳没有地理位置信息或者为局域网，不能视为有效节点
				case res.Hops[availableTTL][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "" &&
					// 一个跃点在中国大陆，另外一个跃点在其他地区，则可以推断出数据包跨境
					chinaMainland(res.Hops[availableTTL][i]) != chinaMainland(res.Hops[ttl][i]):
					// TODO: 将先后2跳跃点信息汇报给API，以完善相关数据
					hopProbesMap[i] = Aboard
				}
			} else {
				hopProbesMap[i] = General
			}
		}
	}

	return hopProbesMap
}

func ClassicPrinter(res *trace.Result, ttl int) {
	fmt.Print(ttl + 1)
	hopsTypeMap := makeHopsType(res, ttl)
	for i := range res.Hops[ttl] {
		HopPrinter(res.Hops[ttl][i], hopsTypeMap[i])
	}
}
