package ai

import (
	"context"
	"encoding/json"
	"errors"
	"os"
	"strings"

	"github.com/rs/zerolog/log"
	openai "github.com/sashabaranov/go-openai"

	"pluja.dev/kycnot.me/database"
)

var sysPrompt = `As a specialized analyzer of Terms and Conditions and Privacy Policies of cryptocurrency exchanges and services, your task is to review the provided legal documents in HTML format. Adhere to the following guidelines:

1. Condense the information, avoid redundancies, and preserve meaning.
2. Translate complex legal jargon into simpler terms, ensuring both accuracy and brevity.
3. You are a privacy advocate, and you think privacy is a human right.
4. Never make your own assumptions.
5. If the document does not explicitly mention something, the 'warning' field MUST be 'false'.
6. Take a deep breath and work on this problem step-by-step.

Use this JSON structure for your analysis and do not add any additional items:

{
	"analysis": [
		{
			"title": "Transaction Monitoring",
			"task": "Determine if the service monitors user transactions or activities, in regards to cryptocurrency. If not, warning is false.",
			"warning": boolean,
            "details": string, // A description in regard to the title and task. Provide citations when possible. Never make assumptions.
            "section": string // The section(s) where you got this from.
		},
		{
			"title": "User Identification",
			"task": "Determine if  users are required to verify their identity. If not, warning is false.",
			// ...
		},
		{
			"title": "3rd Party Data Sharing",
			"task": "Determine if  the service shares user data with third parties. If not, warning is false."
			// ...
		},
		{
			"title": "Data sharing with authorities",
			"task": "Determine if  user data is shared with authorities, law enforcement, or government agencies. If not, warning is false."
			// ...
		},
		{
			"title": "Logging",
			"task": "Determine if the service logs user data, including IP addresses and/or transactions. If not, warning is false."ç
			// ...
		},
		{
			"title": "Blocking of funds",
			"task": "Determine if  the service can block or freeze the user funds, in relation to money or cryptocurrency. If not, warning is false."
			// ...
		},
		{
			"title": "Account termination/blocking",
			"task": "Determine if user accounts could be terminated or blocked, in cases such as suspicious source of funds or transactions. If not, warning is false."
			// ...
		},
		{
			"title": "Transaction flagging",
			"task": "Determine if  the service has a system for flagging suspicious money/criptocurrency transactions. If not, warning is false."
			// ...
		}
	]
}
`

func GetTosReviews(text string) ([]database.TosReview, error) {
	if len(text) < 10 {
		return nil, errors.New("empty text")
	}

	promptPrice := 0.01
	completionPrice := 0.03
	model := openai.GPT4Turbo1106

	// Call the OpenAI API
	var highlights []database.TosReview
	client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
	resp, err := client.CreateChatCompletion(
		context.Background(),
		openai.ChatCompletionRequest{
			Model:          model,
			ResponseFormat: &openai.ChatCompletionResponseFormat{Type: openai.ChatCompletionResponseFormatTypeJSONObject},
			Messages: []openai.ChatCompletionMessage{
				{
					Role:    openai.ChatMessageRoleSystem,
					Content: sysPrompt,
				},
				{
					Role:    openai.ChatMessageRoleUser,
					Content: text,
				},
			},
		},
	)
	if err != nil {
		log.Debug().Err(err).Msg("Could not get response from OpenAI")
		return highlights, err
	}

	log.Printf("Total Tokens: %v", resp.Usage.TotalTokens)
	log.Printf("Price for this request: $%v", float64(resp.Usage.PromptTokens/1000)*promptPrice+float64(resp.Usage.CompletionTokens/1000)*completionPrice)

	if len(resp.Choices) == 0 {
		return highlights, nil
	}

	highlights, err = jsonToHighlights(resp.Choices[0].Message.Content)
	if err != nil {
		return highlights, err
	}
	return highlights, nil
}

func jsonToHighlights(jsonStr string) ([]database.TosReview, error) {
	jsonStr = strings.TrimPrefix(jsonStr, "```json\n")
	jsonStr = strings.TrimSuffix(jsonStr, "\n```")
	var highlights []database.TosReview
	// Extract the `analysis` array from the JSON string and unmarshal it into the highlights slice.

	var m map[string]json.RawMessage // use RawMessage for delayed decoding
	err := json.Unmarshal([]byte(jsonStr), &m)
	if err != nil {
		return highlights, err
	}

	tosAnalysis, ok := m["analysis"]
	if !ok {
		return highlights, errors.New("key 'analysis' not found in JSON")
	}

	err = json.Unmarshal(tosAnalysis, &highlights)
	if err != nil {
		return highlights, err
	}

	return highlights, nil
}
