package infra

import (
	"os"
	"path/filepath"
	"testing"
)

// TestMigrationIntegration covers the full create -> up -> status -> down -> status cycle.
func TestMigrationIntegration(t *testing.T) {
	t.Run("ciclo completo create up status down status", func(t *testing.T) {
		db := openMigrationTestDB(t)
		dir := t.TempDir()

		// Step 1: Create migration files using MigrationCreate
		path1, err := MigrationCreate(dir, "create_users")
		if err != nil {
			t.Fatalf("create 001 failed: %v", err)
		}
		path2, err := MigrationCreate(dir, "create_roles")
		if err != nil {
			t.Fatalf("create 002 failed: %v", err)
		}

		// Fill in actual SQL
		sql1 := "-- 001_create_users.sql\n\n-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY, name TEXT NOT NULL);\n\n-- +down\nDROP TABLE IF EXISTS users;\n"
		if err := os.WriteFile(path1, []byte(sql1), 0o644); err != nil {
			t.Fatalf("write sql1: %v", err)
		}
		sql2 := "-- 002_create_roles.sql\n\n-- +up\nCREATE TABLE roles (id TEXT PRIMARY KEY, label TEXT NOT NULL);\n\n-- +down\nDROP TABLE IF EXISTS roles;\n"
		if err := os.WriteFile(path2, []byte(sql2), 0o644); err != nil {
			t.Fatalf("write sql2: %v", err)
		}

		// Step 2: Parse and validate
		content1, _ := os.ReadFile(filepath.Join(dir, "001_create_users.sql"))
		content2, _ := os.ReadFile(filepath.Join(dir, "002_create_roles.sql"))
		m1, err := MigrationParse("001_create_users.sql", string(content1))
		if err != nil {
			t.Fatalf("parse 001: %v", err)
		}
		m2, err := MigrationParse("002_create_roles.sql", string(content2))
		if err != nil {
			t.Fatalf("parse 002: %v", err)
		}
		validationErrs := MigrationValidate([]Migration{m1, m2})
		if len(validationErrs) > 0 {
			t.Fatalf("validate failed: %v", validationErrs)
		}

		// Step 3: Apply up
		applied, err := MigrationUp(db, dir)
		if err != nil {
			t.Fatalf("up failed: %v", err)
		}
		if len(applied) != 2 {
			t.Errorf("up: expected 2 applied, got %d", len(applied))
		}

		// Step 4: Check status — all applied
		statuses, err := MigrationGetStatus(db, dir)
		if err != nil {
			t.Fatalf("status after up failed: %v", err)
		}
		if len(statuses) != 2 {
			t.Errorf("status: expected 2, got %d", len(statuses))
		}
		for _, s := range statuses {
			if !s.Applied {
				t.Errorf("version %d should be applied", s.Version)
			}
		}

		// Step 5: Revert the last migration
		reverted, err := MigrationDown(db, 1)
		if err != nil {
			t.Fatalf("down failed: %v", err)
		}
		if len(reverted) != 1 || reverted[0].Version != 2 {
			t.Errorf("down: expected version 2, got %v", reverted)
		}

		// Step 6: Check status — one applied, one pending
		statuses2, err := MigrationGetStatus(db, dir)
		if err != nil {
			t.Fatalf("status after down failed: %v", err)
		}
		if len(statuses2) != 2 {
			t.Errorf("status2: expected 2, got %d", len(statuses2))
		}
		// Version 1 should be applied, version 2 pending
		for _, s := range statuses2 {
			switch s.Version {
			case 1:
				if !s.Applied {
					t.Errorf("version 1 should still be applied")
				}
			case 2:
				if s.Applied {
					t.Errorf("version 2 should be pending after down")
				}
			}
		}

		// Step 7: Re-apply — should apply version 2 again
		applied2, err := MigrationUp(db, dir)
		if err != nil {
			t.Fatalf("second up failed: %v", err)
		}
		if len(applied2) != 1 || applied2[0].Version != 2 {
			t.Errorf("second up: expected version 2, got %v", applied2)
		}
	})
}
