package database

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	_ "github.com/mattn/go-sqlite3"
	"github.com/your-username/todo/src/config"
)

// Database interface defines the methods required for task storage and analysis
type Database interface {
	Close() error
	AddTask(ctx context.Context, title string, body string) (int64, error)
	UpdateTask(ctx context.Context, id int64, title string, body string) error
	CompleteTask(ctx context.Context, id int) error
	GetTasks(ctx context.Context, includeCompleted bool) ([]Task, error)
	GetTaskAnalysis(ctx context.Context, taskID int) (*Analysis, error)
	StoreAnalysis(ctx context.Context, analysis *Analysis) error
}

// SQLiteDB implements the Database interface
type SQLiteDB struct {
	db *sql.DB
}

// Task represents a todo task
type Task struct {
	ID        int64
	Title     string
	Body      string
	Completed bool
	CreatedAt time.Time
}

// Analysis represents an AI analysis of a task
type Analysis struct {
	TaskID     int64
	Result     string
	AnalyzedAt time.Time
}

func NewDatabase(cfg config.DatabaseConfig) (Database, error) {
	db, err := sql.Open("sqlite3", cfg.Path)
	if err != nil {
		return nil, fmt.Errorf("error opening database: %w", err)
	}

	// Configure connection pool
	db.SetMaxOpenConns(cfg.MaxOpenConns)
	db.SetMaxIdleConns(cfg.MaxIdleConns)
	db.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetime) * time.Minute)

	// Initialize schema
	if err := initSchema(db); err != nil {
		db.Close()
		return nil, fmt.Errorf("error initializing schema: %w", err)
	}

	return &SQLiteDB{db: db}, nil
}

func initSchema(db *sql.DB) error {
	_, err := db.Exec(`
		CREATE TABLE IF NOT EXISTS tasks (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			title TEXT NOT NULL,
			body TEXT,
			completed BOOLEAN DEFAULT FALSE,
			created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
		);
		
		CREATE TABLE IF NOT EXISTS analysis (
			task_id INTEGER,
			result TEXT,
			analyzed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			FOREIGN KEY(task_id) REFERENCES tasks(id)
		);

		CREATE INDEX IF NOT EXISTS idx_tasks_completed ON tasks(completed);
		CREATE INDEX IF NOT EXISTS idx_analysis_task_id ON analysis(task_id);
	`)
	return err
}

func (d *SQLiteDB) Close() error {
	return d.db.Close()
}

func (d *SQLiteDB) AddTask(ctx context.Context, title string, body string) (int64, error) {
	result, err := d.db.ExecContext(ctx,
		"INSERT INTO tasks (title, body) VALUES (?, ?)",
		title, body)
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

func (d *SQLiteDB) UpdateTask(ctx context.Context, id int64, title string, body string) error {
	result, err := d.db.ExecContext(ctx,
		"UPDATE tasks SET title = ?, body = ? WHERE id = ?",
		title, body, id)
	if err != nil {
		return err
	}
	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}
	if rows == 0 {
		return sql.ErrNoRows
	}
	return nil
}

func (d *SQLiteDB) CompleteTask(ctx context.Context, id int) error {
	_, err := d.db.ExecContext(ctx,
		"UPDATE tasks SET completed = TRUE WHERE id = ?",
		id)
	return err
}

func (d *SQLiteDB) GetTasks(ctx context.Context, includeCompleted bool) ([]Task, error) {
	query := "SELECT id, title, body, completed, created_at FROM tasks"
	if !includeCompleted {
		query += " WHERE completed = FALSE"
	}
	query += " ORDER BY created_at DESC"

	rows, err := d.db.QueryContext(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var tasks []Task
	for rows.Next() {
		var t Task
		err := rows.Scan(&t.ID, &t.Title, &t.Body, &t.Completed, &t.CreatedAt)
		if err != nil {
			return nil, err
		}
		tasks = append(tasks, t)
	}
	return tasks, rows.Err()
}

func (d *SQLiteDB) GetTaskAnalysis(ctx context.Context, taskID int) (*Analysis, error) {
	var analysis Analysis
	err := d.db.QueryRowContext(ctx, `
		SELECT task_id, result, analyzed_at 
		FROM analysis 
		WHERE task_id = ? 
		ORDER BY analyzed_at DESC LIMIT 1`,
		taskID).Scan(&analysis.TaskID, &analysis.Result, &analysis.AnalyzedAt)
	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return &analysis, nil
}

func (d *SQLiteDB) StoreAnalysis(ctx context.Context, analysis *Analysis) error {
	_, err := d.db.ExecContext(ctx,
		"INSERT INTO analysis (task_id, result, analyzed_at) VALUES (?, ?, ?)",
		analysis.TaskID, analysis.Result, analysis.AnalyzedAt)
	return err
}
