package services

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

// AIService handles AI-related operations via LLM Gateway
type AIService struct {
	llmGatewayURL string
	httpClient    *http.Client
}

// NewAIService creates a new AIService
func NewAIService(llmGatewayURL string) *AIService {
	return &AIService{
		llmGatewayURL: llmGatewayURL,
		httpClient: &http.Client{
			Timeout: 120 * time.Second, // AI requests can take longer
		},
	}
}

// ChatMessage represents a message in the chat format
type ChatMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// ChatRequest represents a request to the LLM Gateway
type ChatRequest struct {
	Messages []ChatMessage `json:"messages"`
	Model    string        `json:"model,omitempty"`
}

// ChatResponse represents a response from the LLM Gateway
type ChatResponse struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
	Error string `json:"error,omitempty"`
}

// GenerateExamVariant generates a variant of an exam using AI
func (s *AIService) GenerateExamVariant(ctx context.Context, originalContent string, variationType string) (string, error) {
	var prompt string

	switch variationType {
	case "rewrite":
		prompt = fmt.Sprintf(`Du bist ein erfahrener Lehrer. Erstelle eine Nachschreibeversion der folgenden Klausur/Arbeit.

WICHTIG:
- Behalte den EXAKTEN Schwierigkeitsgrad bei
- Formuliere die Textaufgaben um (andere Worte, gleiche Bedeutung)
- Bei Rechenaufgaben: Andere Zahlen, gleicher Rechenweg, gleiche Schwierigkeit
- Behalte die Punkteverteilung und Struktur bei
- Die neue Version soll für Schüler sein, die bei der Originalklausur gefehlt haben

Original-Klausur:
%s

Erstelle nun die Nachschreibeversion:`, originalContent)

	case "alternative":
		prompt = fmt.Sprintf(`Du bist ein erfahrener Lehrer. Erstelle eine komplett alternative Version der folgenden Klausur zum gleichen Thema.

WICHTIG:
- Gleiches Thema und Lernziele
- Komplett neue Aufgaben (nicht nur umformuliert)
- Gleicher Schwierigkeitsgrad
- Gleiche Punkteverteilung und Struktur
- Andere Beispiele und Szenarien verwenden

Original-Klausur (als Referenz für Thema und Schwierigkeitsgrad):
%s

Erstelle nun die alternative Version:`, originalContent)

	case "similar":
		prompt = fmt.Sprintf(`Du bist ein erfahrener Lehrer. Erstelle eine ähnliche Übungsarbeit basierend auf der folgenden Klausur.

WICHTIG:
- Geeignet als Übungsmaterial für die Klausurvorbereitung
- Ähnliche Aufgabentypen wie im Original
- Gleicher Schwierigkeitsgrad
- Kann als Hausaufgabe oder zur Selbstübung verwendet werden

Original-Klausur:
%s

Erstelle nun die Übungsarbeit:`, originalContent)

	default:
		return "", fmt.Errorf("unknown variation type: %s", variationType)
	}

	return s.sendChatRequest(ctx, prompt)
}

// ImproveExamContent improves exam content (grammar, clarity)
func (s *AIService) ImproveExamContent(ctx context.Context, content string) (string, error) {
	prompt := fmt.Sprintf(`Du bist ein erfahrener Lehrer. Verbessere den folgenden Klausurtext:

WICHTIG:
- Korrigiere Rechtschreibung und Grammatik
- Verbessere die Klarheit der Aufgabenstellungen
- Ändere NICHT den Schwierigkeitsgrad oder Inhalt
- Ändere NICHT die Punkteverteilung
- Behalte die Struktur bei

Original:
%s

Verbesserte Version:`, content)

	return s.sendChatRequest(ctx, prompt)
}

// GenerateGradeFeedback generates feedback for a student based on their grades
func (s *AIService) GenerateGradeFeedback(ctx context.Context, studentName string, grades map[string]float64, semester int) (string, error) {
	gradesJSON, _ := json.Marshal(grades)

	prompt := fmt.Sprintf(`Du bist ein erfahrener Klassenlehrer. Erstelle eine kurze, konstruktive Zeugnis-Bemerkung für folgenden Schüler:

Schüler: %s
Halbjahr: %d
Noten: %s

WICHTIG:
- Maximal 3-4 Sätze
- Konstruktiv und ermutigend formulieren
- Stärken hervorheben
- Bei Bedarf dezente Verbesserungsvorschläge
- Professioneller, sachlicher Ton (Zeugnis-tauglich)
- Keine übertriebenen Lobpreisungen

Erstelle die Bemerkung:`, studentName, semester, string(gradesJSON))

	return s.sendChatRequest(ctx, prompt)
}

// sendChatRequest sends a request to the LLM Gateway
func (s *AIService) sendChatRequest(ctx context.Context, prompt string) (string, error) {
	reqBody := ChatRequest{
		Messages: []ChatMessage{
			{Role: "user", Content: prompt},
		},
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return "", fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, "POST", s.llmGatewayURL+"/v1/chat/completions", bytes.NewBuffer(jsonBody))
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := s.httpClient.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("LLM Gateway returned status %d: %s", resp.StatusCode, string(body))
	}

	var chatResp ChatResponse
	if err := json.Unmarshal(body, &chatResp); err != nil {
		return "", fmt.Errorf("failed to parse response: %w", err)
	}

	if chatResp.Error != "" {
		return "", fmt.Errorf("LLM Gateway error: %s", chatResp.Error)
	}

	if len(chatResp.Choices) == 0 {
		return "", fmt.Errorf("no response from LLM")
	}

	return chatResp.Choices[0].Message.Content, nil
}

// HealthCheck checks if the LLM Gateway is available
func (s *AIService) HealthCheck(ctx context.Context) error {
	req, err := http.NewRequestWithContext(ctx, "GET", s.llmGatewayURL+"/health", nil)
	if err != nil {
		return err
	}

	resp, err := s.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("LLM Gateway unhealthy: status %d", resp.StatusCode)
	}

	return nil
}
