package infra

import (
	"testing"
)

func TestMigrationStatus(t *testing.T) {
	t.Run("migraciones en disco pero no en BD aparecen como pending", func(t *testing.T) {
		db := openMigrationTestDB(t)
		dir := t.TempDir()

		writeMigrationFile(t, dir, "001_create_users.sql",
			"-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n")
		writeMigrationFile(t, dir, "002_create_roles.sql",
			"-- +up\nCREATE TABLE roles (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS roles;\n")

		statuses, err := MigrationGetStatus(db, dir)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(statuses) != 2 {
			t.Fatalf("expected 2 statuses, got %d", len(statuses))
		}
		for _, s := range statuses {
			if s.Applied {
				t.Errorf("version %d should be pending, got applied", s.Version)
			}
		}
	})

	t.Run("migraciones aplicadas aparecen con Applied=true y AppliedAt", func(t *testing.T) {
		db := openMigrationTestDB(t)
		dir := t.TempDir()

		writeMigrationFile(t, dir, "001_create_users.sql",
			"-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n")
		writeMigrationFile(t, dir, "002_create_roles.sql",
			"-- +up\nCREATE TABLE roles (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS roles;\n")

		if _, err := MigrationUp(db, dir); err != nil {
			t.Fatalf("up failed: %v", err)
		}

		statuses, err := MigrationGetStatus(db, dir)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(statuses) != 2 {
			t.Fatalf("expected 2 statuses, got %d", len(statuses))
		}
		for _, s := range statuses {
			if !s.Applied {
				t.Errorf("version %d should be applied, got pending", s.Version)
			}
			if s.AppliedAt.IsZero() {
				t.Errorf("version %d AppliedAt should not be zero", s.Version)
			}
		}
	})

	t.Run("migraciones aplicadas sin archivo en disco aparecen como orphaned", func(t *testing.T) {
		db := openMigrationTestDB(t)
		dir := t.TempDir()

		writeMigrationFile(t, dir, "001_create_users.sql",
			"-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n")

		if _, err := MigrationUp(db, dir); err != nil {
			t.Fatalf("up failed: %v", err)
		}

		// Remove file from disk but migration is applied in DB
		// Now check status with an empty dir
		emptyDir := t.TempDir()
		statuses, err := MigrationGetStatus(db, emptyDir)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(statuses) != 1 {
			t.Fatalf("expected 1 status (orphaned), got %d", len(statuses))
		}
		s := statuses[0]
		if !s.Applied {
			t.Errorf("orphaned migration should have Applied=true")
		}
		if !containsStr(s.Name, "orphaned") {
			t.Errorf("orphaned migration name should contain 'orphaned', got %q", s.Name)
		}
	})

	t.Run("base de datos sin tabla _migrations retorna todas como pending", func(t *testing.T) {
		db := openMigrationTestDB(t)
		dir := t.TempDir()

		writeMigrationFile(t, dir, "001_create_users.sql",
			"-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n")

		// Do NOT call MigrationUp — _migrations table doesn't exist
		statuses, err := MigrationGetStatus(db, dir)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(statuses) != 1 {
			t.Fatalf("expected 1 status, got %d", len(statuses))
		}
		if statuses[0].Applied {
			t.Errorf("migration should be pending when _migrations does not exist")
		}
	})
}
