package tencent_map

import (
	"encoding/json"
	"fmt"
	"git.rosy.net.cn/baseapi/utils"
	"net/http"
)

// TencentCoordinateChange 腾讯坐标转换(其他坐标转换为腾讯坐标)
func (a *API) TencentCoordinateChange(param *TencentCoordinateChangeReq) ([]*LocationsCoordinateObj, error) {
	requestParam := utils.Struct2Map(param, "", false)
	requestParam["sig"] = a.signParams(requestParam, TencentCoordinateApi)
	result, err := a.AccessAPI(BaseUrl, TencentCoordinateApi, http.MethodGet, requestParam)
	if err != nil {
		return nil, err
	}

	resultByte, err := json.Marshal(result)
	if err != nil {
		return nil, err
	}
	data := &TencentCoordinateChangeRes{}
	if err = json.Unmarshal(resultByte, data); err != nil {
		return nil, err
	}

	if data.Status != 0 {
		return nil, fmt.Errorf("%s", data.Message)
	}

	locations := make([]*LocationsCoordinateObj, 0, 0)
	for _, v := range data.Locations {
		locations = append(locations, &LocationsCoordinateObj{
			Lat: v.Lat.String(),
			Lng: v.Lng.String(),
		})
	}

	return locations, nil
}

// TencentCyclingPlanning 腾讯电动车骑行规划
func (a *API) TencentCyclingPlanning(param *TencentCyclingPlanningReq) (distance int64, duration int64, coordinatePoint []string, err error) {
	requestParam := utils.Struct2Map(param, "", false)
	requestParam["sig"] = a.signParams(requestParam, TencentCyclingPlanning)
	result, err := a.AccessAPI(BaseUrl, TencentCyclingPlanning, http.MethodGet, requestParam)
	if err != nil {
		return 0, 0, nil, err
	}
	resultByte, err := json.Marshal(result)
	if err != nil {
		return 0, 0, nil, err
	}
	data := &TencentCyclingPlanningRes{}
	if err = json.Unmarshal(resultByte, data); err != nil {
		return 0, 0, nil, err
	}

	if data.Status != 0 {
		return 0, 0, nil, err
	}

	for _, v := range data.Result["routes"] {
		distance = v.Distance
		duration = v.Duration

		pointList := make([]string, 0, len(v.Polyline))
		pointList = append(pointList, v.Polyline[0].String())
		pointList = append(pointList, v.Polyline[1].String())
		for i := 2; i < len(v.Polyline); i++ {
			point1 := utils.Str2Float64(pointList[i-2])
			point2, _ := v.Polyline[i].Float64()

			point3 := point1 + point2/float64(1000000)
			point4 := fmt.Sprintf("%.6f", point3)
			pointList = append(pointList, point4)
		}

		for i := 0; i < len(pointList); i += 2 {
			coordinatePoint = append(coordinatePoint, fmt.Sprintf("%s,%s", pointList[i+1], pointList[i]))
		}

		return distance, duration, coordinatePoint, nil
	}
	return 0, 0, nil, fmt.Errorf("骑行计划获取异常")
}

// WalkingDistance 获取两点之间的步行距离
func (a *API) WalkingDistance(param *TencentCyclingPlanningReq) (distance int64, err error) {
	requestParam := utils.Struct2Map(param, "", false)
	requestParam["sig"] = a.signParams(requestParam, TencentWalkingPlanning)
	result, err := a.AccessAPI(BaseUrl, TencentWalkingPlanning, http.MethodGet, requestParam)
	if err != nil {
		return 0, err
	}
	resultByte, err := json.Marshal(result)
	if err != nil {
		return 0, err
	}
	data := &TencentCyclingPlanningRes{}
	if err = json.Unmarshal(resultByte, data); err != nil {
		return 0, err
	}

	if data.Status != 0 {
		return 0, err
	}

	for _, v := range data.Result["routes"] {
		return v.Distance, nil
		//duration = v.Duration
		//
		//pointList := make([]string, 0, len(v.Polyline))
		//pointList = append(pointList, v.Polyline[0].String())
		//pointList = append(pointList, v.Polyline[1].String())
		//for i := 2; i < len(v.Polyline); i++ {
		//	point1 := utils.Str2Float64(pointList[i-2])
		//	point2, _ := v.Polyline[i].Float64()
		//	pointList = append(pointList, fmt.Sprintf("%.6f", point1+point2/float64(1000000)))
		//}
		//
		//for i := 0; i < len(pointList); i += 2 {
		//	coordinatePoint = append(coordinatePoint, fmt.Sprintf("%s,%s", pointList[i+1], pointList[i]))
		//}
		//globals.SugarLogger.Debugf("调换后 : %s", utils.Format4Output(coordinatePoint, false))
		//
		//return distance, duration, coordinatePoint, nil
	}
	return 0, fmt.Errorf("步行计划获取异常")
}

// GetCoordinateFromAddress 根据地址或者城市code获取坐标已经城市编码
func (a *API) GetCoordinateFromAddress(address string, cityInfo string) (lng, lat float64, districtCode int, districtName string, err error) {
	if address == "" {
		return 0, 0, 0, "", fmt.Errorf("地址信息不能为空")
	}

	requestParam := map[string]interface{}{
		"address": address,
		"key":     a.key,
	}
	requestParam["sig"] = a.signParams(requestParam, TencentGeoAddress2Code)
	result, err := a.AccessAPI(BaseUrl, TencentGeoAddress2Code, http.MethodGet, requestParam)
	if err != nil {
		return 0, 0, 0, "", err
	}

	data := &AddressGeoCoderChangeRes{}
	if err := utils.Map2StructByJson(result, data, false); err != nil {
		return 0, 0, 0, "", err
	}
	lng, _ = data.Result.Location.Lng.Float64()
	lat, _ = data.Result.Location.Lat.Float64()

	return lng, lat, utils.Str2Int(data.Result.AdInfo.AdCode), data.Result.AddressComponents.District, nil
}

// GeoCodeRegeoSingle 根据坐标获取地址信息
func (a *API) GeoCodeRegeoSingle(lng, lat float64, radius int, isExt bool, poiTypes []string, roadLevel, homeOrCorp int) (coordInfo *Codes2AddressRes, err error) {
	param := map[string]interface{}{
		"location": utils.Float64ToStr(lat) + "," + utils.Float64ToStr(lng),
		"key":      a.key,
	}
	param["sig"] = a.signParams(param, TencentCoder2Address)
	result, err := a.AccessAPI(BaseUrl, TencentCoder2Address, http.MethodGet, param)

	resultByte, err := json.Marshal(result)
	if err != nil {
		return nil, err
	}

	if err = json.Unmarshal(resultByte, &coordInfo); err != nil {
		return nil, err
	}
	return coordInfo, err
}

// GetDistricts 行政区划查询 subdistrict子级行政区 keywords 关键字
func (a *API) GetDistricts(subDistrict int, keywords string, level int) (districtList []*District, err error) {
	// 之前是使用的高德地图更新的,高德更新的地图在直辖市的时候,比腾讯地图多了一行数据
	// 行政区划长时间不会改变,所以不在更新本地存储的行政区划直接跳过
	// 110000	北京市	0	1	010	100001	131	1	0	1	0
	// 110100	北京市	110000	2	010	1	0	1	730	0	0
	if subDistrict == 3 && keywords == "" {
		return nil, fmt.Errorf("高德转腾讯,暂时不做修改")
		/*param := map[string]interface{}{
			"struct_type": 1,
			"key":         a.key,
		}
		param["sig"] = a.signParams(param, TencentGetDistrictList)
		result, err := a.AccessAPI(BaseUrl, TencentGetDistrictList, http.MethodGet, param)

		resultByte, err := json.Marshal(result)
		if err != nil {
			return nil, err
		}

		administrativeDivision := &AdministrativeDivision{}
		if err = json.Unmarshal(resultByte, administrativeDivision); err != nil {
			return nil, err
		}

		return administrativeDivision.Result, err*/
	}

	if keywords != "" {
		return a.GetSecondaryDivision(subDistrict, keywords, level)
	}

	return nil, fmt.Errorf("参数异常")
}

// GetSecondaryDivision 获取二级行政区划 keywords 是父级code
func (a *API) GetSecondaryDivision(number int, keywords string, level int) ([]*District, error) {
	param := map[string]interface{}{
		"key": a.key,
		"id":  keywords,
	}
	param["sig"] = a.signParams(param, TencentGetChildrenList)
	result, err := a.AccessAPI(BaseUrl, TencentGetChildrenList, http.MethodGet, param)
	if err != nil {
		return nil, err
	}
	resultByte, err := json.Marshal(result)
	if err != nil {
		return nil, err
	}

	districtGetChildren := &DistrictGetChildren{}
	if err = json.Unmarshal(resultByte, districtGetChildren); err != nil {
		return nil, err
	}
	if districtGetChildren.Status != 0 {
		return nil, fmt.Errorf("%s", districtGetChildren.Message)
	}

	resultData := make([]*District, 0, 0)
	for _, v := range districtGetChildren.Result[0] {
		parentCode := &District{
			Adcode:    v.Id,
			Lng:       0.0,
			Lat:       0.0,
			CityCode:  "",
			Level:     level,
			Name:      v.Fullname,
			Districts: nil,
		}
		parentCode.Lng, _ = v.Location.Lng.Float64()
		parentCode.Lat, _ = v.Location.Lat.Float64()
		if number == 2 {
			parentCode.Districts, _ = a.GetSecondaryDivision(1, v.Id, level+1)
		}
		resultData = append(resultData, parentCode)
	}

	return resultData, nil
}

// BatchWalkingDistance 批量获取两点之间的步行距离
func (a *API) BatchWalkingDistance(srcLng, srcLat float64, destCoords []*Coordinate) (distanceList []float64, err error) {
	for _, v := range destCoords {
		distance, err := a.WalkingDistance(&TencentCyclingPlanningReq{
			Key:  a.key,
			From: fmt.Sprintf("%f,%f", srcLat, srcLng),
			To:   fmt.Sprintf("%f,%f", v.Lat, v.Lng),
		})
		if err != nil {
			return nil, err
		}
		distanceList = append(distanceList, utils.Int64ToFloat64(distance))
	}

	return distanceList, err
}

// GetCoordinateDistrictCode 获取坐标点所在行政区划
func (a *API) GetCoordinateDistrictCode(lng, lat float64) (districtCode int) {
	result, err := a.GeoCodeRegeoSingle(lng, lat, 0, false, nil, 0, 0)
	if err == nil {
		districtCode = utils.Str2Int(result.Result.AdInfo.Adcode)
		// 这个是因为老代码使用搞的地图获取这两个市的时候没有分区,place表做了一个假的分区,这边为了统一
		if result.Result.AdInfo.District == "东莞市" || result.Result.AdInfo.District == "中山市" {
			districtCode += 9000000 // FakeDistrictPadding
		}
		return
	}
	return 0
}

// GetCoordinateTownInfo 根据坐标获取城市名称和坐标
func (a *API) GetCoordinateTownInfo(lng, lat float64) (townName, townCode string) {
	result, err := a.GeoCodeRegeoSingle(lng, lat, 0, false, nil, 0, 0)
	if err == nil {
		if name, ok := result.Result.AddressReference.(map[string]interface{})["town"].(map[string]interface{})["title"]; ok {
			townName = name.(string)
		}
		if name, ok := result.Result.AddressReference.(map[string]interface{})["town"].(map[string]interface{})["id"]; ok {
			townCode = name.(string) + "000"
		}
	}
	return
}

// GetCoordinateCityInfo 根据坐标获取
func (a *API) GetCoordinateCityInfo(lng, lat float64) (cityName, cityCode string) {
	result, err := a.GeoCodeRegeoSingle(lng, lat, 0, false, nil, 0, 0)
	if err == nil {
		cityName = result.Result.AdInfo.City
		// cityCode 老版本高德地图获取到的是电话的区号,但是这个返回值没有使用,暂时不做处理
		cityCode = result.Result.AdInfo.CityCode
	}

	return
}
