package main

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-resty/resty/v2"
	"math/rand"
	"net/http"
	"strings"
	"sync"
	"time"
)

// 初始化有效的github token列表
func initValidTokenList() {
	//为了安全起见，应该等待请求完成并处理其响应。
	var wg sync.WaitGroup
	for _, token := range configFile.CopilotConfig.Token {
		wg.Add(1)
		go func(token string) {
			defer wg.Done()
			if getGithubApi(token) {
				validTokenList[token] = true
			}
		}(token)
	}
	wg.Wait()
}

// 请求github api
func getGithubApi(token string) bool {
	githubApiCount++
	// 设置请求头
	headers := map[string]string{
		"Authorization": "token " + token,
		/*"editor-version":        c.GetHeader("editor-version"),
		"editor-plugin-version": c.GetHeader("editor-plugin-version"),
		"user-agent":            c.GetHeader("user-agent"),
		"accept":                c.GetHeader("accept"),
		"accept-encoding":       c.GetHeader("accept-encoding"),*/
	}
	// 发起GET请求
	response, err := resty.New().R().
		SetHeaders(headers).
		Get(configFile.CopilotConfig.GithubApiUrl)
	if err != nil {
		// 处理请求错误
		return false
	}
	// 判断响应状态码
	if response.StatusCode() == http.StatusOK {
		// 响应状态码为200 OK
		respDataMap := map[string]interface{}{}
		err = json.Unmarshal(response.Body(), &respDataMap)
		if err != nil {
			// 处理JSON解析错误
			return false
		}
		//token map
		tokenMap[token] = respDataMap
		return true
	} else {
		// 处理其他状态码
		delete(validTokenList, token)
		return false
	}
}

// 获取copilot token
func getGithubToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		requestCount++
		if err := verifyRequest(c); err != nil {
			badRequest(c)
			return
		}
		token := getRandomToken(validTokenList)
		if respDataMap, exists := getTokenData(token); exists {
			if !isTokenExpired(respDataMap) {
				proxyResp(c, respDataMap)
				return
			}
		}
		if getGithubApi(token) {
			proxyResp(c, tokenMap[token])
		} else {
			badRequest(c)
		}
	}
}

// 验证请求代理请求token
func verifyRequest(c *gin.Context) error {
	if configFile.Verification != "" {
		token := c.GetHeader("Authorization")
		tokenStr := strings.ReplaceAll(token, " ", "")
		configCert := strings.ReplaceAll(configFile.Verification, " ", "")
		if tokenStr != "token"+configCert {
			return errors.New("verification failed")
		}
	}
	return nil
}

// 从map中获取github token对应的copilot token
func getTokenData(token string) (map[string]interface{}, bool) {
	respDataMap, exists := tokenMap[token]
	return respDataMap, exists
}

// 检测copilot token是否过期
func isTokenExpired(respDataMap map[string]interface{}) bool {
	if expiresAt, ok := respDataMap["expires_at"].(float64); ok {
		currentTime := time.Now().Unix()
		expiresAtInt64 := int64(expiresAt)
		return expiresAtInt64 <= currentTime+60
	}
	return true
}

// 重置请求计数
func resetRequestCount() {
	requestCountMutex.Lock()
	defer requestCountMutex.Unlock()
	requestCount = 0
	successCount = 0
}

// 从map中随机获取一个github token
func getRandomToken(m map[string]bool) string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	if len(keys) == 0 {
		return "" // 返回空字符串或处理其他错误情况
	}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	randomIndex := r.Intn(len(keys))
	return keys[randomIndex]
}
