package ai

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"paraclub-ai-mailer/config"
	"paraclub-ai-mailer/internal/logger"

	"github.com/sirupsen/logrus"
)

type AI struct {
	config config.AIConfig
	client *http.Client
}

type OpenRouterRequest struct {
	Model       string    `json:"model"`
	Messages    []Message `json:"messages"`
	Temperature float32   `json:"temperature"`
	MaxTokens   int       `json:"max_tokens"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type OpenRouterResponse struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
}

func New(cfg config.AIConfig) *AI {
	return &AI{
		config: cfg,
		client: &http.Client{},
	}
}

func (a *AI) detectLanguage(emailContent string) (string, error) {
	logger.WithField("emailContentLength", len(emailContent)).Debug("Starting language detection")

	systemMsg := "You are a language detection assistant. Analyze the provided text and respond ONLY with the language name (e.g., 'English', 'German', 'French', etc.). No other text or explanation."
	userMsg := fmt.Sprintf("Detect the language of this text:\n\n%s", emailContent)

	messages := []Message{
		{Role: "system", Content: systemMsg},
		{Role: "user", Content: userMsg},
	}

	response, err := a.makeAPIRequest(messages)
	if err != nil {
		return "", fmt.Errorf("language detection failed: %v", err)
	}

	// The response should be just the language code
	langCode := response
	logger.WithField("detectedLanguage", langCode).Debug("Language detection completed")
	return langCode, nil
}

func (a *AI) GenerateReply(emailContent string, contextContent map[string]string) (string, error) {
	logger.WithFields(logrus.Fields{
		"emailContentLength": len(emailContent),
		"contextUrls":        len(contextContent),
	}).Debug("Starting AI reply generation")

	// First, detect the language
	lang, err := a.detectLanguage(emailContent)
	if err != nil {
		return "", err
	}

	// Prepare context from all URLs
	var context string
	for url, content := range contextContent {
		context += fmt.Sprintf("\nContext from %s:\n%s\n", url, content)
		logger.WithFields(logrus.Fields{
			"url":           url,
			"contentLength": len(content),
		}).Debug("Added context from URL")
	}

	// Prepare the system message with language-specific instruction
	systemMsg := fmt.Sprintf(`You are a helpful assistant who responds to emails.
Your primary goal is to answer the user's query (found in the 'Email Body') by primarily using the information available in the 'Additional Context' and your general knowledge.
While the 'Email Body' provides the question, your answer should be synthesized from the context and your understanding, not by directly repeating or solely relying on unverified information from the 'Email Body' itself.

Instructions:
- Language: Your response must be entirely in %s, regardless of the language used in the email content or context.
- Format: Your reply must be raw HTML. Use appropriate HTML tags for structure and styling.
- Markdown: Do NOT wrap the HTML in markdown code blocks (e.g., %s).
- Extraneous Text: Do not include a subject line. Do not include explanations, commentary, or any extra text that is not part of the direct answer.
- Closing: Avoid generic closing statements like "If you have further questions...". Focus solely on answering the email.
`, lang, "```html ... ```")
	logger.WithFields(logrus.Fields{
		"systemprompt": systemMsg,
	}).Debug("Generating system prompt")
	userMsg := fmt.Sprintf("### Additional Context:\n%s\n\n### Email Body:\n%s", context, emailContent)

	messages := []Message{
		{Role: "system", Content: systemMsg},
		{Role: "user", Content: userMsg},
	}

	aiResponse, err := a.makeAPIRequest(messages)
	if err != nil {
		// Error already logged by makeAPIRequest, just propagate
		return "", err
	}
	logger.WithField("rawAIResponse", aiResponse).Debug("Received raw response from AI")
	return aiResponse, nil
}

func (a *AI) makeAPIRequest(messages []Message) (string, error) {
	const maxRetries = 3
	var lastErr error

	for attempt := 0; attempt < maxRetries; attempt++ {
		logger.WithField("attempt", attempt+1).Debug("Making API request attempt")

		reqBody := OpenRouterRequest{
			Model:       a.config.Model,
			Messages:    messages,
			Temperature: a.config.Temperature,
			MaxTokens:   a.config.MaxTokens,
		}

		logger.WithFields(logrus.Fields{
			"model":       reqBody.Model,
			"temperature": reqBody.Temperature,
			"maxTokens":   reqBody.MaxTokens,
		}).Debug("Prepared API request")

		jsonData, err := json.Marshal(reqBody)
		if err != nil {
			logger.WithError(err).Error("Failed to marshal request body")
			return "", err
		}

		req, err := http.NewRequest("POST", "https://openrouter.ai/api/v1/chat/completions", bytes.NewBuffer(jsonData))
		if err != nil {
			logger.WithError(err).Error("Failed to create HTTP request")
			return "", err
		}

		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.config.OpenRouterAPIKey))

		resp, err := a.client.Do(req)
		if err != nil {
			logger.WithFields(logrus.Fields{
				"error":   err,
				"attempt": attempt + 1,
			}).Debug("API request failed, will retry")
			lastErr = err
			continue
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			logger.WithFields(logrus.Fields{
				"statusCode": resp.StatusCode,
				"attempt":    attempt + 1,
			}).Debug("API returned non-200 status code")
			lastErr = fmt.Errorf("OpenRouter API returned status code: %d", resp.StatusCode)
			continue
		}

		var result OpenRouterResponse
		if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
			logger.WithFields(logrus.Fields{
				"error":   err,
				"attempt": attempt + 1,
			}).Debug("Failed to decode API response")
			lastErr = err
			continue
		}

		if len(result.Choices) == 0 || result.Choices[0].Message.Content == "" {
			logger.WithField("attempt", attempt+1).Debug("Received empty response from API")
			lastErr = fmt.Errorf("empty response received")
			continue
		}

		responseLength := len(result.Choices[0].Message.Content)
		logger.WithFields(logrus.Fields{
			"attempt":        attempt + 1,
			"responseLength": responseLength,
		}).Debug("Successfully generated AI reply")
		return result.Choices[0].Message.Content, nil
	}

	logger.WithFields(logrus.Fields{
		"maxRetries": maxRetries,
		"lastError":  lastErr,
	}).Error("Failed to generate AI reply after all attempts")
	return "", fmt.Errorf("failed after %d attempts, last error: %v", maxRetries, lastErr)
}
