package openai

import (
	"encoding/json"
	"os"
	"strings"
)

const (
	// https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation#latest-preview-api-releases
	AzureApiVersion    = "2024-10-21"
	BaseHost           = "api.openai.com"
	OpenAI_Endpoint    = "https://api.openai.com/v1/chat/completions"
	Github_Marketplace = "https://models.inference.ai.azure.com/chat/completions"
)

var (
	Custom_Endpoint    string
	AIGateWay_Endpoint string // "https://gateway.ai.cloudflare.com/v1/431ba10f11200d544922fbca177aaa7f/openai/openai/chat/completions"
)

func init() {
	if os.Getenv("OpenAI_Endpoint") != "" {
		Custom_Endpoint = os.Getenv("OpenAI_Endpoint")
	}
	if os.Getenv("AIGateWay_Endpoint") != "" {
		AIGateWay_Endpoint = os.Getenv("AIGateWay_Endpoint")
	}
}

// Vision Content
type VisionContent struct {
	Type     string          `json:"type,omitempty"`
	Text     string          `json:"text,omitempty"`
	ImageURL *VisionImageURL `json:"image_url,omitempty"`
}
type VisionImageURL struct {
	URL    string `json:"url,omitempty"`
	Detail string `json:"detail,omitempty"`
}

type ChatCompletionMessage struct {
	Role    string `json:"role"`
	Content any    `json:"content"`
	Name    string `json:"name,omitempty"`
	// MultiContent []VisionContent
}

type FunctionDefinition struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Parameters  any    `json:"parameters"`
}

type Tool struct {
	Type     string              `json:"type"`
	Function *FunctionDefinition `json:"function,omitempty"`
}

type StreamOption struct {
	IncludeUsage bool `json:"include_usage,omitempty"`
}

type ChatCompletionRequest struct {
	Model            string                  `json:"model"`
	Messages         []ChatCompletionMessage `json:"messages"`
	MaxTokens        int                     `json:"max_tokens,omitempty"`
	Temperature      float64                 `json:"temperature,omitempty"`
	TopP             float64                 `json:"top_p,omitempty"`
	N                int                     `json:"n,omitempty"`
	Stream           bool                    `json:"stream"`
	Stop             []string                `json:"stop,omitempty"`
	PresencePenalty  float64                 `json:"presence_penalty,omitempty"`
	FrequencyPenalty float64                 `json:"frequency_penalty,omitempty"`
	LogitBias        map[string]int          `json:"logit_bias,omitempty"`
	User             string                  `json:"user,omitempty"`
	// Functions        []FunctionDefinition       `json:"functions,omitempty"`
	// FunctionCall     any                        `json:"function_call,omitempty"`
	Tools             []Tool `json:"tools,omitempty"`
	ParallelToolCalls bool   `json:"parallel_tool_calls,omitempty"`
	// ToolChoice any    `json:"tool_choice,omitempty"`
	StreamOptions *StreamOption `json:"stream_options,omitempty"`
}

func (c ChatCompletionRequest) ToByteJson() []byte {
	bytejson, _ := json.Marshal(c)
	return bytejson
}

type ToolCall struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	Function struct {
		Name      string `json:"name"`
		Arguments string `json:"arguments"`
	} `json:"function"`
}

type ChatCompletionResponse struct {
	ID      string `json:"id,omitempty"`
	Object  string `json:"object,omitempty"`
	Created int    `json:"created,omitempty"`
	Model   string `json:"model,omitempty"`
	Choices []struct {
		Index   int `json:"index,omitempty"`
		Message struct {
			Role      string     `json:"role,omitempty"`
			Content   string     `json:"content,omitempty"`
			ToolCalls []ToolCall `json:"tool_calls,omitempty"`
		} `json:"message,omitempty"`
		Logprobs     string `json:"logprobs,omitempty"`
		FinishReason string `json:"finish_reason,omitempty"`
	} `json:"choices,omitempty"`
	Usage struct {
		PromptTokens        int `json:"prompt_tokens,omitempty"`
		CompletionTokens    int `json:"completion_tokens,omitempty"`
		TotalTokens         int `json:"total_tokens,omitempty"`
		PromptTokensDetails struct {
			CachedTokens int `json:"cached_tokens,omitempty"`
			AudioTokens  int `json:"audio_tokens,omitempty"`
		} `json:"prompt_tokens_details,omitempty"`
		CompletionTokensDetails struct {
			ReasoningTokens          int `json:"reasoning_tokens,omitempty"`
			AudioTokens              int `json:"audio_tokens,omitempty"`
			AcceptedPredictionTokens int `json:"accepted_prediction_tokens,omitempty"`
			RejectedPredictionTokens int `json:"rejected_prediction_tokens,omitempty"`
		} `json:"completion_tokens_details,omitempty"`
	} `json:"usage,omitempty"`
	SystemFingerprint string `json:"system_fingerprint,omitempty"`
}

type Choice struct {
	Index int `json:"index"`
	Delta struct {
		Role      string     `json:"role"`
		Content   string     `json:"content"`
		ToolCalls []ToolCall `json:"tool_calls"`
	} `json:"delta"`
	FinishReason string `json:"finish_reason"`
	Usage        struct {
		PromptTokens     int `json:"prompt_tokens"`
		CompletionTokens int `json:"completion_tokens"`
		TotalTokens      int `json:"total_tokens"`
	} `json:"usage"`
}

type ChatCompletionStreamResponse struct {
	ID      string   `json:"id"`
	Object  string   `json:"object"`
	Created int      `json:"created"`
	Model   string   `json:"model"`
	Choices []Choice `json:"choices"`
}

func (c *ChatCompletionStreamResponse) ByteJson() []byte {
	bytejson, _ := json.Marshal(c)
	return bytejson
}

func modelmap(in string) string {
	// gpt-3.5-turbo -> gpt-35-turbo
	if strings.Contains(in, ".") {
		return strings.ReplaceAll(in, ".", "")
	}
	return in
}

type ErrResponse struct {
	Error struct {
		Message string `json:"message"`
		Code    string `json:"code"`
	} `json:"error"`
}

func (e *ErrResponse) ByteJson() []byte {
	bytejson, _ := json.Marshal(e)
	return bytejson
}
