package infra

import (
	"database/sql"
	"testing"
	"testing/fstest"

	_ "github.com/mattn/go-sqlite3"
)

// makeFS builds a simple in-memory FS with the given path→content pairs.
func makeFS(files map[string]string) fstest.MapFS {
	m := make(fstest.MapFS, len(files))
	for path, content := range files {
		m[path] = &fstest.MapFile{Data: []byte(content)}
	}
	return m
}

func TestApplyMigrations(t *testing.T) {
	t.Run("una migracion se aplica correctamente", func(t *testing.T) {
		db, err := sql.Open("sqlite3", ":memory:")
		if err != nil {
			t.Fatal(err)
		}
		defer db.Close()

		fsys := makeFS(map[string]string{
			"migrations/001_init.sql": `CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT);`,
		})
		if err := ApplyMigrations(db, fsys, ""); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		// Verify table exists.
		var count int
		if err := db.QueryRow(`SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='items'`).Scan(&count); err != nil {
			t.Fatal(err)
		}
		if count != 1 {
			t.Errorf("table 'items' not created; count=%d", count)
		}
	})

	t.Run("multiples migraciones en orden", func(t *testing.T) {
		db, err := sql.Open("sqlite3", ":memory:")
		if err != nil {
			t.Fatal(err)
		}
		defer db.Close()

		fsys := makeFS(map[string]string{
			"migrations/001_init.sql":        `CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY);`,
			"migrations/002_add_column.sql":  `ALTER TABLE t ADD COLUMN val TEXT;`,
		})
		if err := ApplyMigrations(db, fsys, ""); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		// Insert using the new column.
		if _, err := db.Exec(`INSERT INTO t (id, val) VALUES (1, 'hello')`); err != nil {
			t.Fatalf("insert failed (column may be missing): %v", err)
		}
	})

	t.Run("error real se propaga", func(t *testing.T) {
		db, err := sql.Open("sqlite3", ":memory:")
		if err != nil {
			t.Fatal(err)
		}
		defer db.Close()

		fsys := makeFS(map[string]string{
			"migrations/001_bad.sql": `THIS IS NOT VALID SQL;`,
		})
		if err := ApplyMigrations(db, fsys, ""); err == nil {
			t.Errorf("expected error for invalid SQL, got nil")
		}
	})

	t.Run("ALTER TABLE ADD COLUMN duplicado se ignora", func(t *testing.T) {
		db, err := sql.Open("sqlite3", ":memory:")
		if err != nil {
			t.Fatal(err)
		}
		defer db.Close()

		setup := `CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, val TEXT);`
		if _, err := db.Exec(setup); err != nil {
			t.Fatal(err)
		}
		// Run ALTER that would fail with "duplicate column".
		fsys := makeFS(map[string]string{
			"migrations/001_dup.sql": `ALTER TABLE t ADD COLUMN val TEXT;`,
		})
		if err := ApplyMigrations(db, fsys, ""); err != nil {
			t.Errorf("duplicate column error should be ignored, got: %v", err)
		}
	})
}
