package router

import (
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"opencatd-open/pkg/claude"
	oai "opencatd-open/pkg/openai"
	"opencatd-open/store"
	"os"
	"time"

	"github.com/gin-gonic/gin"
)

var (
	baseUrl       = "https://api.openai.com"
	GPT3Dot5Turbo = "gpt-3.5-turbo"
	GPT4          = "gpt-4"
)

// type ChatCompletionMessage struct {
// 	Role    string `json:"role"`
// 	Content string `json:"content"`
// 	Name    string `json:"name,omitempty"`
// }

// type ChatCompletionRequest struct {
// 	Model            string                  `json:"model"`
// 	Messages         []ChatCompletionMessage `json:"messages"`
// 	MaxTokens        int                     `json:"max_tokens,omitempty"`
// 	Temperature      float32                 `json:"temperature,omitempty"`
// 	TopP             float32                 `json:"top_p,omitempty"`
// 	N                int                     `json:"n,omitempty"`
// 	Stream           bool                    `json:"stream,omitempty"`
// 	Stop             []string                `json:"stop,omitempty"`
// 	PresencePenalty  float32                 `json:"presence_penalty,omitempty"`
// 	FrequencyPenalty float32                 `json:"frequency_penalty,omitempty"`
// 	LogitBias        map[string]int          `json:"logit_bias,omitempty"`
// 	User             string                  `json:"user,omitempty"`
// }

// type ChatCompletionChoice struct {
// 	Index        int                   `json:"index"`
// 	Message      ChatCompletionMessage `json:"message"`
// 	FinishReason string                `json:"finish_reason"`
// }

// type ChatCompletionResponse struct {
// 	ID      string                 `json:"id"`
// 	Object  string                 `json:"object"`
// 	Created int64                  `json:"created"`
// 	Model   string                 `json:"model"`
// 	Choices []ChatCompletionChoice `json:"choices"`
// 	Usage   struct {
// 		PromptTokens     int `json:"prompt_tokens"`
// 		CompletionTokens int `json:"completion_tokens"`
// 		TotalTokens      int `json:"total_tokens"`
// 	} `json:"usage"`
// }

func init() {
	if openai_endpoint := os.Getenv("openai_endpoint"); openai_endpoint != "" {
		log.Println(fmt.Sprintf("replace %s to %s", baseUrl, openai_endpoint))
		baseUrl = openai_endpoint
	}
}

func HandleProxy(c *gin.Context) {
	var (
		localuser bool
	)
	auth := c.Request.Header.Get("Authorization")
	if len(auth) > 7 && auth[:7] == "Bearer " {
		localuser = store.IsExistAuthCache(auth[7:])
		c.Set("localuser", auth[7:])
	}
	if c.Request.URL.Path == "/v1/complete" {
		if localuser {
			claude.ClaudeProxy(c)
			return
		} else {
			HandleReverseProxy(c, "api.anthropic.com")
			return
		}

	}
	if c.Request.URL.Path == "/v1/audio/transcriptions" {
		oai.WhisperProxy(c)
		return
	}
	if c.Request.URL.Path == "/v1/audio/speech" {
		oai.SpeechProxy(c)
		return
	}

	if c.Request.URL.Path == "/v1/images/generations" {
		oai.DallEProxy(c)
		return
	}

	if c.Request.URL.Path == "/v1/realtime" {
		oai.RealTimeProxy(c)
		return
	}

	if c.Request.URL.Path == "/v1/chat/completions" {
		if localuser {
			if store.KeysCache.ItemCount() == 0 {
				c.JSON(http.StatusBadGateway, gin.H{"error": gin.H{
					"message": "No Api-Key Available",
				}})
				return
			}

			ChatHandler(c)
			return
		}
	} else {
		HandleReverseProxy(c, "api.openai.com")
		return
	}

}

func HandleReverseProxy(c *gin.Context, targetHost string) {
	proxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			req.URL.Scheme = "https"
			req.URL.Host = targetHost
		},
		Transport: &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).DialContext,
			ForceAttemptHTTP2:     true,
			MaxIdleConns:          100,
			IdleConnTimeout:       90 * time.Second,
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
			TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
		},
	}

	req, err := http.NewRequest(c.Request.Method, c.Request.URL.Path, c.Request.Body)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"error": err.Error()})
		return
	}
	req.Header = c.Request.Header

	proxy.ServeHTTP(c.Writer, req)
	return
}
