package ai

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
)

// ConversationManager handles CRUD operations for AI conversations stored in SQLite.
type ConversationManager struct {
	db *sql.DB
}

// NewConversationManager creates a manager backed by the given database.
func NewConversationManager(db *sql.DB) *ConversationManager {
	return &ConversationManager{db: db}
}

// Create starts a new conversation and returns its summary.
func (m *ConversationManager) Create(model string) (*ConversationSummary, error) {
	id := uuid.NewString()
	now := time.Now()

	_, err := m.db.Exec(
		`INSERT INTO conversations (id, title, model, messages, tokens_in, tokens_out, created_at, updated_at)
		 VALUES (?, ?, ?, '[]', 0, 0, ?, ?)`,
		id, "New conversation", model, now, now,
	)
	if err != nil {
		return nil, fmt.Errorf("create conversation: %w", err)
	}

	return &ConversationSummary{
		ID:        id,
		Title:     "New conversation",
		Model:     model,
		CreatedAt: now,
		TokensIn:  0,
		TokensOut: 0,
	}, nil
}

// AddMessage appends a message to the conversation's message list.
func (m *ConversationManager) AddMessage(convId string, msg Message) error {
	// Get existing messages
	messages, err := m.GetMessages(convId)
	if err != nil {
		return err
	}

	messages = append(messages, msg)
	data, err := json.Marshal(messages)
	if err != nil {
		return fmt.Errorf("marshal messages: %w", err)
	}

	_, err = m.db.Exec(
		"UPDATE conversations SET messages = ?, updated_at = ? WHERE id = ?",
		string(data), time.Now(), convId,
	)
	if err != nil {
		return fmt.Errorf("update messages: %w", err)
	}

	// Auto-title from first user message
	if len(messages) == 1 && msg.Role == "user" {
		title := extractTitle(msg)
		if title != "" {
			m.db.Exec("UPDATE conversations SET title = ? WHERE id = ?", title, convId)
		}
	}

	return nil
}

// GetMessages returns all messages in a conversation.
func (m *ConversationManager) GetMessages(convId string) ([]Message, error) {
	var messagesJSON string
	err := m.db.QueryRow("SELECT messages FROM conversations WHERE id = ?", convId).Scan(&messagesJSON)
	if err == sql.ErrNoRows {
		return nil, fmt.Errorf("conversation %s not found", convId)
	}
	if err != nil {
		return nil, fmt.Errorf("get messages: %w", err)
	}

	var messages []Message
	if err := json.Unmarshal([]byte(messagesJSON), &messages); err != nil {
		return nil, fmt.Errorf("unmarshal messages: %w", err)
	}
	return messages, nil
}

// List returns all conversations ordered by most recent.
func (m *ConversationManager) List() ([]ConversationSummary, error) {
	rows, err := m.db.Query(
		`SELECT id, title, model, tokens_in, tokens_out, created_at
		 FROM conversations ORDER BY updated_at DESC`,
	)
	if err != nil {
		return nil, fmt.Errorf("list conversations: %w", err)
	}
	defer rows.Close()

	var summaries []ConversationSummary
	for rows.Next() {
		var s ConversationSummary
		var title sql.NullString
		if err := rows.Scan(&s.ID, &title, &s.Model, &s.TokensIn, &s.TokensOut, &s.CreatedAt); err != nil {
			return nil, fmt.Errorf("scan conversation: %w", err)
		}
		if title.Valid {
			s.Title = title.String
		}
		summaries = append(summaries, s)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate conversations: %w", err)
	}

	if summaries == nil {
		summaries = []ConversationSummary{}
	}
	return summaries, nil
}

// Delete removes a conversation and all its messages.
func (m *ConversationManager) Delete(convId string) error {
	result, err := m.db.Exec("DELETE FROM conversations WHERE id = ?", convId)
	if err != nil {
		return fmt.Errorf("delete conversation: %w", err)
	}
	affected, _ := result.RowsAffected()
	if affected == 0 {
		return fmt.Errorf("conversation %s not found", convId)
	}
	return nil
}

// UpdateTokenUsage adds to the token counters for a conversation.
func (m *ConversationManager) UpdateTokenUsage(convId string, tokensIn, tokensOut int) error {
	_, err := m.db.Exec(
		`UPDATE conversations
		 SET tokens_in = tokens_in + ?, tokens_out = tokens_out + ?, updated_at = ?
		 WHERE id = ?`,
		tokensIn, tokensOut, time.Now(), convId,
	)
	if err != nil {
		return fmt.Errorf("update token usage: %w", err)
	}
	return nil
}

// extractTitle generates a title from the first user message (truncated to 80 chars).
func extractTitle(msg Message) string {
	for _, block := range msg.Content {
		if block.Type == "text" && block.Text != "" {
			title := block.Text
			if len(title) > 80 {
				title = title[:77] + "..."
			}
			return title
		}
	}
	return ""
}
