package service

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/AlekSi/pointer"
	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
	"github.com/go-nunu/nunu-layout-advanced/internal/model"
	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
	"maps"
	"sort"
	"strconv"
	"strings"

	"github.com/spf13/cast"
)

type FormatterService interface {
	FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, output map[string]v1.SendGameShieldBackend, keyCounter int) (string, error)
	FormatPort(ctx context.Context, req interface{}) []int
	OldFormat(ctx context.Context, req *[]model.GameShieldBackend) (map[string]v1.SendGameShieldBackend, error)
	TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error)
	Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error)
	ValidateBackendData(ctx context.Context, mapData map[string]v1.SendGameShieldBackend, hostId int) error
}

func NewFormatterService(
	service *Service,
	gameShieldPublicIpService GameShieldPublicIpService,
	gameShieldBackendRepository repository.GameShieldBackendRepository,
	hostService HostService,

) FormatterService {
	return &formatterService{
		Service:                     service,
		gameShieldPublicIpService:   gameShieldPublicIpService,
		gameShieldBackendRepository: gameShieldBackendRepository,
		hostService:                 hostService,
	}
}

type formatterService struct {
	*Service
	gameShieldPublicIpService   GameShieldPublicIpService
	gameShieldBackendRepository repository.GameShieldBackendRepository
	hostService                 HostService
}

func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, oldFormat map[string]v1.SendGameShieldBackend, keyCounter int) (string, error) {
	formData, err := service.TidyFormatBackendData(ctx, req, keyCounter)
	for k := range formData {
		// 获取副本
		tempItem := formData[k]
		tempItem.Type = ""
		tempItem.Remark = ""
		formData[k] = tempItem // 将修改后的副本存回 map
	}
	if err != nil {
		return "", err
	}
	maps.Copy(formData, oldFormat)

	// 验证
	err = service.ValidateBackendData(ctx, formData, req.HostId)
	if err != nil {
		return "", err
	}

	sortedOutput, err := service.Sort(ctx, formData)
	if err != nil {
		return "", err
	}
	jsonBytes, err := json.MarshalIndent(sortedOutput, "", " ")
	if err != nil {
		return "", err
	}

	return string(jsonBytes), nil
}

// FormatPort 格式化端口
func (service *formatterService) FormatPort(ctx context.Context, req interface{}) []int {
	if req == nil {
		return []int{}
	}

	reqStr := cast.ToString(req)

	if reqStr == "" {
		return []int{}
	}

	reqStr = strings.ReplaceAll(reqStr, "，", ",")

	// 分割字符串并转换为整数
	var res []int
	for _, v := range strings.Split(reqStr, ",") {
		// 去除空格
		v = strings.TrimSpace(v)
		if v != "" {
			port := cast.ToInt(v)
			res = append(res, port)
		}
	}
	return res
}

// OldFormat 旧格式
func (service *formatterService) OldFormat(ctx context.Context, req *[]model.GameShieldBackend) (map[string]v1.SendGameShieldBackend, error) {
	res := make(map[string]v1.SendGameShieldBackend)
	var UdpSessionTimeout string
	var MaxBandwidth string
	for _, v := range *req {
		addr := fmt.Sprintf("%s:%s", v.SourceMachineIP, v.ConnectPort)
		sdkPort, err := strconv.Atoi(v.SdkPort)
		if err != nil {
			return nil, err
		}
		if v.Protocol == "udp" {
			UdpSessionTimeout = "300s"
			v.ProxyAddr = ""
		} else {
			UdpSessionTimeout = ""
		}
		keyName := fmt.Sprintf("key%d", v.KeySort)
		if v.Type != "pc" {
			v.SdkIp = ""
		}
		if v.MaxBandwidth == 1 {
			MaxBandwidth = "12.5m"
		} else {
			MaxBandwidth = ""
		}
		if v.Protocol != "http" {
			v.Host = ""
		}
		res[keyName] = v1.SendGameShieldBackend{
			Addr:              []string{addr},
			Protocol:          v.Protocol,
			ProxyAddr:         v.ProxyAddr,
			SdkPort:           sdkPort,
			UdpSessionTimeout: UdpSessionTimeout,
			SdkIp:             v.SdkIp,
			MaxBandwidth:      MaxBandwidth,
			Host:              v.Host,
		}
	}
	return res, nil
}

func (service *formatterService) TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error) {
	output := make(map[string]v1.SendGameShieldBackend)
	userIp, err := service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid)
	if err != nil {
		return nil, err
	}
	for _, item := range req.Items {
		// 提取必要字段
		sourceIP := item.SourceMachineIP // 假设结构体中有这个字段
		if sourceIP == "" {
			return nil, fmt.Errorf("没有有效源IP的配置") // 跳过没有有效源IP的配置
		}

		protocol := item.Protocol // 假设结构体中有这个字段
		if protocol == "" {
			return nil, fmt.Errorf("没有有效协议的配置") // 跳过没有有效协议的配置
		}
		// 获取端口数组
		conPorts := service.FormatPort(ctx, item.ConnectPort)
		sdkPorts := service.FormatPort(ctx, item.SdkPort)

		// 验证端口数量
		if len(sdkPorts) > 0 && len(conPorts) != len(sdkPorts) {
			return nil, fmt.Errorf("端口数量不匹配")
		}

		// 处理每一对端口
		for i := 0; i < len(conPorts); i++ {
			keyCounter++
			key := fmt.Sprintf("key%d", keyCounter)

			// 使用数组中的具体端口
			addr := fmt.Sprintf("%s:%d", sourceIP, conPorts[i])

			itemMap := v1.SendGameShieldBackend{
				Addr:     []string{addr},
				Protocol: protocol,
				Type:     item.Type,
			}

			// 设置主机名（如果存在）
			if item.Protocol == "http" && item.Host != "" {
				itemMap.Host = item.Host
			}

			// 根据协议设置不同属性
			if protocol != "udp" {
				if item.RealIp == "agent" {
					itemMap.AgentAddr = fmt.Sprintf("%s:%s", sourceIP, "23350")
				}
				itemMap.ProxyAddr = userIp + ":32353"

			} else {
				itemMap.ProxyAddr = ""
				itemMap.UdpSessionTimeout = "300s"
			}
			if item.Type != "pc" {
				itemMap.SdkIp = ""
			} else {
				itemMap.SdkIp = item.SdkIp
			}

			if pointer.GetInt(item.MaxBandwidth) == 1 {
				itemMap.MaxBandwidth = "12.5m"
			} else {
				itemMap.MaxBandwidth = ""
			}
			// 设置SDK端口 - 使用数组中的具体端口
			if len(sdkPorts) != 0 {
				if sdkPorts[i] <= 1024 {
					if item.Type == "mobile" {
						return nil, fmt.Errorf("移动端不支持SSH端口")
					}
				}
				itemMap.SdkPort = sdkPorts[i]
			}
			if len(item.Remark) > 0 {
				itemMap.Remark = item.Remark
			}
			output[key] = itemMap
		}
	}

	return output, nil
}
func (service *formatterService) Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error) {
	var keys []int
	for key := range mapData {
		intKey, err := strconv.Atoi(strings.TrimPrefix(key, "key"))
		if err != nil {
			return nil, err
		}
		keys = append(keys, intKey)
	}

	// 2. 排序键
	sort.Ints(keys)
	// 3. 创建一个新的 output 切片或 map 来存储排序后的值
	sortedOutput := make(map[string]v1.SendGameShieldBackend)

	// 4. 按排序后的键遍历 map，并存储对应的值到 sortedOutput
	for _, key := range keys {
		sortedOutput["key"+strconv.Itoa(key)] = mapData["key"+strconv.Itoa(key)]
	}
	return sortedOutput, nil
}

// 验证后端数据
func (service *formatterService) ValidateBackendData(ctx context.Context, data map[string]v1.SendGameShieldBackend, hostId int) error {
	// 获取配置限制
	configCount, err := service.hostService.GetGameShieldConfig(ctx, hostId)
	if err != nil {
		return fmt.Errorf("获取配置限制失败: %w", err)
	}

	// 提取源机IP和SDK端口
	sourceIPs := make(map[string]bool)
	ruleEntriesCount := int64(0)
	maxBandwidthCount := int64(0)

	// 分协议检查SDK端口
	tcpHttpPorts := make(map[int]bool) // TCP和HTTP共用
	udpPorts := make(map[int]bool)     // UDP单独使用

	for _, item := range data {
		// 计算规则条目数
		ruleEntriesCount += int64(len(item.Addr))

		// 计算源机IP数
		for _, addr := range item.Addr {
			parts := strings.Split(addr, ":")
			if len(parts) > 0 {
				sourceIPs[parts[0]] = true
			}
		}

		// 计算最大带宽设置数
		if item.MaxBandwidth != "" {
			maxBandwidthCount++
		}

		// 根据协议类型检查SDK端口重复
		if item.SdkPort != 0 {
			// 根据协议字段来判断SDK端口是否重复
			switch strings.ToUpper(item.Protocol) {
			case "TCP", "HTTP":
				if tcpHttpPorts[item.SdkPort] {
					return fmt.Errorf("TCP/HTTP SDK端口%d重复，每个端口只能配置一次", item.SdkPort)
				}
				tcpHttpPorts[item.SdkPort] = true
			case "UDP":
				if udpPorts[item.SdkPort] {
					return fmt.Errorf("UDP SDK端口%d重复，每个端口只能配置一次", item.SdkPort)
				}
				udpPorts[item.SdkPort] = true
			default:
				return fmt.Errorf("不支持的协议类型: %s", item.Protocol)
			}
		}
	}

	// 验证源机数量
	if int64(len(sourceIPs)) > configCount.SourceMachinesCount {
		return fmt.Errorf("超出最大源机数量，当前配置允许%d个源机，合并后有%d个源机",
			configCount.SourceMachinesCount, len(sourceIPs))
	}

	// 验证规则条目数
	if ruleEntriesCount > configCount.RuleEntriesCount {
		return fmt.Errorf("超出最大规则数量，当前配置允许%d个规则，合并后有%d个规则",
			configCount.RuleEntriesCount, ruleEntriesCount)
	}

	// 验证最大带宽设置数
	if maxBandwidthCount > configCount.MaxBandwidthCount {
		return fmt.Errorf("超出最大带宽数量，当前配置允许%d个带宽设置，合并后有%d个",
			configCount.MaxBandwidthCount, maxBandwidthCount)
	}

	return nil
}
