// PUBLIC DOMAIN - NO LICENSE, NO WARRANTY
// Copyright 2025 TimeHexOn & foxhop & russell@unturf
// https://www.permacomputer.com

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

type ModelsResponse struct {
	Data []struct {
		ID string `json:"id"`
	} `json:"data"`
}

func main() {
	fmt.Println("=== uncloseai. Go Client (Official OpenAI SDK) ===\n")

	// Discover endpoints from environment variables
	modelEndpoint1 := os.Getenv("MODEL_ENDPOINT_1")
	modelEndpoint2 := os.Getenv("MODEL_ENDPOINT_2")
	ttsEndpoint1 := os.Getenv("TTS_ENDPOINT_1")

	if modelEndpoint1 == "" || modelEndpoint2 == "" || ttsEndpoint1 == "" {
		fmt.Fprintf(os.Stderr, "ERROR: No models discovered. Set environment variables:\n")
		fmt.Fprintf(os.Stderr, "  MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, TTS_ENDPOINT_1\n")
		os.Exit(1)
	}

	// Discover models from endpoint 1
	fmt.Printf("Discovering models from %s...\n", modelEndpoint1)
	resp1, err := http.Get(modelEndpoint1 + "/models")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error discovering models: %v\n", err)
		os.Exit(1)
	}
	defer resp1.Body.Close()

	var models1 ModelsResponse
	if err := json.NewDecoder(resp1.Body).Decode(&models1); err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing models: %v\n", err)
		os.Exit(1)
	}
	model1ID := models1.Data[0].ID
	fmt.Printf("Model 1: %s\n\n", model1ID)

	// Discover models from endpoint 2
	fmt.Printf("Discovering models from %s...\n", modelEndpoint2)
	resp2, err := http.Get(modelEndpoint2 + "/models")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error discovering models: %v\n", err)
		os.Exit(1)
	}
	defer resp2.Body.Close()

	var models2 ModelsResponse
	if err := json.NewDecoder(resp2.Body).Decode(&models2); err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing models: %v\n", err)
		os.Exit(1)
	}
	model2ID := models2.Data[0].ID
	fmt.Printf("Model 2: %s\n\n", model2ID)

	// Non-streaming chat with Model 1
	fmt.Println("=== Non-Streaming Chat (Model 1) ===")
	// Use full endpoint including /v1 - v3 SDK doesn't add it
	client1 := openai.NewClient(
		option.WithBaseURL(modelEndpoint1),
		option.WithAPIKey("dummy-key"),
	)

	chatResponse1, err := client1.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
		Model: openai.ChatModel(model1ID),
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("Give a Python Fizzbuzz solution in one line of code?"),
		},
		Temperature: openai.Float(0.5),
		MaxTokens:   openai.Int(150),
	})

	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Printf("Response: %s\n\n", chatResponse1.Choices[0].Message.Content)
	}

	// Streaming chat with Model 1
	fmt.Println("=== Streaming Chat (Model 1) ===")
	stream1 := client1.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
		Model: openai.ChatModel(model1ID),
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("Explain quantum entanglement in one sentence."),
		},
		Temperature: openai.Float(0.5),
		MaxTokens:   openai.Int(150),
	})

	fmt.Print("Response: ")
	for stream1.Next() {
		chunk := stream1.Current()
		if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" {
			fmt.Print(chunk.Choices[0].Delta.Content)
		}
	}

	if err := stream1.Err(); err != nil {
		fmt.Printf("\nStream error: %v\n", err)
	}
	fmt.Println("\n")

	// Non-streaming chat with Model 2
	fmt.Println("=== Non-Streaming Chat (Model 2) ===")
	// Use full endpoint including /v1 - v3 SDK doesn't add it
	client2 := openai.NewClient(
		option.WithBaseURL(modelEndpoint2),
		option.WithAPIKey("dummy-key"),
	)

	chatResponse2, err := client2.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
		Model: openai.ChatModel(model2ID),
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("Write a JavaScript function to check if a number is prime"),
		},
		Temperature: openai.Float(0.5),
		MaxTokens:   openai.Int(150),
	})

	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Printf("Response: %s\n\n", chatResponse2.Choices[0].Message.Content)
	}

	// Streaming chat with Model 2
	fmt.Println("=== Streaming Chat (Model 2) ===")
	stream2 := client2.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
		Model: openai.ChatModel(model2ID),
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("Give a Python Fizzbuzz solution in one line of code?"),
		},
		Temperature: openai.Float(0.5),
		MaxTokens:   openai.Int(150),
	})

	fmt.Print("Response: ")
	for stream2.Next() {
		chunk := stream2.Current()
		if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" {
			fmt.Print(chunk.Choices[0].Delta.Content)
		}
	}

	if err := stream2.Err(); err != nil {
		fmt.Printf("\nStream error: %v\n", err)
	}
	fmt.Println("\n")

	// TTS example
	fmt.Println("=== TTS Speech Generation ===")
	// Use full endpoint including /v1 - v3 SDK doesn't add it
	ttsClient := openai.NewClient(
		option.WithBaseURL(ttsEndpoint1),
		option.WithAPIKey("dummy-key"),
	)

	response, err := ttsClient.Audio.Speech.New(context.Background(), openai.AudioSpeechNewParams{
		Model: openai.SpeechModelTTS1,
		Voice: openai.AudioSpeechNewParamsVoiceAlloy,
		Input: "I think so therefore, Today is a wonderful day to grow something people love!",
		Speed: openai.Float(0.9),
	})

	if err != nil {
		fmt.Printf("TTS Error: %v\n", err)
	} else {
		defer response.Body.Close()

		out, err := os.Create("speech.mp3")
		if err != nil {
			fmt.Printf("File creation error: %v\n", err)
		} else {
			defer out.Close()
			_, err = io.Copy(out, response.Body)
			if err != nil {
				fmt.Printf("File write error: %v\n", err)
			} else {
				fileInfo, _ := os.Stat("speech.mp3")
				fmt.Printf("[OK] Speech file created: speech.mp3 (%d bytes)\n\n", fileInfo.Size())
			}
		}
	}

	fmt.Println("=== Examples Complete ===")
}
