package services

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"lost-and-found/internal/models"
	"lost-and-found/internal/repositories"
	"net/http"
	"os"
	"strings"

	"gorm.io/gorm"
)

type AIService struct {
	db           *gorm.DB
	chatRepo     *repositories.ChatRepository
	itemRepo     *repositories.ItemRepository
	lostItemRepo *repositories.LostItemRepository
	groqAPIKey   string
	groqModel    string
}

func NewAIService(db *gorm.DB) *AIService {
	model := os.Getenv("GROQ_MODEL")
	if model == "" {
		model = "llama-3.3-70b-versatile" // Default model
	}

	return &AIService{
		db:           db,
		chatRepo:     repositories.NewChatRepository(db),
		itemRepo:     repositories.NewItemRepository(db),
		lostItemRepo: repositories.NewLostItemRepository(db),
		groqAPIKey:   os.Getenv("GROQ_API_KEY"),
		groqModel:    model,
	}
}

type ChatRequest struct {
	Message string `json:"message" binding:"required"`
}

// Groq API Request Structure
type GroqRequest struct {
	Model       string         `json:"model"`
	Messages    []GroqMessage  `json:"messages"`
	Temperature float64        `json:"temperature,omitempty"`
	MaxTokens   int            `json:"max_tokens,omitempty"`
	TopP        float64        `json:"top_p,omitempty"`
	Stream      bool           `json:"stream"`
}

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

// Groq API Response Structure
type GroqResponse struct {
	ID      string `json:"id"`
	Object  string `json:"object"`
	Created int64  `json:"created"`
	Model   string `json:"model"`
	Choices []struct {
		Index   int `json:"index"`
		Message struct {
			Role    string `json:"role"`
			Content string `json:"content"`
		} `json:"message"`
		FinishReason string `json:"finish_reason"`
	} `json:"choices"`
	Usage struct {
		PromptTokens     int `json:"prompt_tokens"`
		CompletionTokens int `json:"completion_tokens"`
		TotalTokens      int `json:"total_tokens"`
	} `json:"usage"`
}

func (s *AIService) ProcessChat(userID uint, message string) (*models.ChatMessage, error) {
	// Build context from user data
	context, err := s.buildUserContext(userID, message)
	if err != nil {
		return nil, err
	}

	// Detect intent
	intent := s.detectIntent(message)

	// Build prompt with context
	systemPrompt := s.buildSystemPrompt()
	userPrompt := s.buildUserPrompt(message, context, intent)

	// Call Groq API
	response, err := s.callGroqAPI(systemPrompt, userPrompt)
	if err != nil {
		return nil, err
	}

	// Save to database
	chat := &models.ChatMessage{
		UserID:          userID,
		Message:         message,
		Response:        response,
		Intent:          intent,
		ConfidenceScore: 85.0,
	}

	if err := s.chatRepo.Create(chat); err != nil {
		return nil, err
	}

	return chat, nil
}

func (s *AIService) buildUserContext(userID uint, message string) (string, error) {
	var context strings.Builder

	// Get user's lost items
	lostItems, _, _ := s.lostItemRepo.FindByUser(userID, 1, 5)
	if len(lostItems) > 0 {
		context.WriteString("\n📋 Barang yang dilaporkan hilang:\n")
		for _, item := range lostItems {
			context.WriteString(fmt.Sprintf("- %s (%s) - Status: %s\n",
				item.Name, item.Category.Name, item.Status))
		}
	}

	// Search for relevant found items if user is looking for something
	if strings.Contains(strings.ToLower(message), "cari") ||
		strings.Contains(strings.ToLower(message), "temukan") {
		items, _, _ := s.itemRepo.FindAll(1, 5, "unclaimed", "", message)
		if len(items) > 0 {
			context.WriteString("\n🔍 Barang ditemukan yang relevan:\n")
			for _, item := range items {
				context.WriteString(fmt.Sprintf("- ID: %d, %s (%s) - Lokasi: %s\n",
					item.ID, item.Name, item.Category.Name, item.Location))
			}
		}
	}

	return context.String(), nil
}

func (s *AIService) detectIntent(message string) string {
	msgLower := strings.ToLower(message)

	searchKeywords := []string{"cari", "temukan", "ada", "lihat", "ditemukan"}
	reportKeywords := []string{"hilang", "kehilangan", "lapor", "laporkan"}
	claimKeywords := []string{"klaim", "ambil", "punya saya", "milik saya"}

	for _, kw := range searchKeywords {
		if strings.Contains(msgLower, kw) {
			return models.IntentSearchItem
		}
	}

	for _, kw := range reportKeywords {
		if strings.Contains(msgLower, kw) {
			return models.IntentReportLost
		}
	}

	for _, kw := range claimKeywords {
		if strings.Contains(msgLower, kw) {
			return models.IntentClaimHelp
		}
	}

	return models.IntentGeneral
}

func (s *AIService) buildSystemPrompt() string {
	return `Kamu adalah asisten AI untuk sistem Lost & Found kampus bernama "FindItBot". 

Tugasmu adalah membantu mahasiswa dan staff dengan:
1. 🔍 Mencari barang yang hilang/ditemukan
2. 📝 Memandu proses pelaporan barang hilang
3. ✅ Menjelaskan proses klaim barang
4. ❓ Menjawab pertanyaan umum tentang sistem

Aturan penting:
- Jawab dengan ramah, profesional, dan membantu
- Gunakan Bahasa Indonesia yang jelas
- Jika ada data barang yang relevan, sebutkan ID dan detailnya
- Untuk pelaporan, tanyakan: nama barang, kategori, lokasi, tanggal hilang, deskripsi
- Untuk klaim, jelaskan proses verifikasi yang diperlukan
- Gunakan emoji yang sesuai untuk memperjelas informasi
- Prioritaskan informasi dari konteks yang diberikan

Contoh respons yang baik:
"🔍 Saya menemukan 2 barang yang mungkin cocok:
1. ID: 123 - Dompet Kulit (Kategori: Wallet) - Ditemukan di Perpustakaan
2. ID: 124 - Dompet Hitam (Kategori: Wallet) - Ditemukan di Kantin

Apakah salah satu dari ini milik Anda? Anda bisa klaim dengan menyebutkan ID barangnya."`
}

func (s *AIService) buildUserPrompt(message, context, intent string) string {
	var prompt strings.Builder

	if context != "" {
		prompt.WriteString("KONTEKS PENGGUNA:\n")
		prompt.WriteString(context)
		prompt.WriteString("\n\n")
	}

	prompt.WriteString(fmt.Sprintf("INTENT TERDETEKSI: %s\n\n", intent))
	prompt.WriteString(fmt.Sprintf("PERTANYAAN: %s\n\n", message))
	prompt.WriteString("Berikan respons yang membantu berdasarkan konteks di atas.")

	return prompt.String()
}

func (s *AIService) callGroqAPI(systemPrompt, userPrompt string) (string, error) {
	if s.groqAPIKey == "" {
		return "", errors.New("GROQ_API_KEY not configured")
	}

	url := "https://api.groq.com/openai/v1/chat/completions"

	reqBody := GroqRequest{
		Model: s.groqModel,
		Messages: []GroqMessage{
			{
				Role:    "system",
				Content: systemPrompt,
			},
			{
				Role:    "user",
				Content: userPrompt,
			},
		},
		Temperature: 0.7,
		MaxTokens:   1024,
		TopP:        0.95,
		Stream:      false,
	}

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

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return "", fmt.Errorf("failed to create request: %v", err)
	}

	req.Header.Set("Authorization", "Bearer "+s.groqAPIKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to call Groq API: %v", err)
	}
	defer resp.Body.Close()

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

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

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

	if len(groqResp.Choices) == 0 {
		return "", errors.New("no response from Groq API")
	}

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

func (s *AIService) GetChatHistory(userID uint, limit int) ([]models.ChatMessageResponse, error) {
	chats, err := s.chatRepo.GetUserChatHistory(userID, limit)
	if err != nil {
		return nil, err
	}

	var responses []models.ChatMessageResponse
	for _, chat := range chats {
		responses = append(responses, chat.ToResponse())
	}

	return responses, nil
}

func (s *AIService) ClearChatHistory(userID uint) error {
	return s.chatRepo.DeleteUserHistory(userID)
}