package postgres

import (
	"os"
	"strconv"
	"strings"
	"testing"
)

func TestMigrationsAreEmbeddedInOrder(t *testing.T) {
	entries, err := migrationsFS.ReadDir("migrations")
	if err != nil {
		t.Fatalf("failed to read migrations directory: %v", err)
	}

	var upFiles []string
	var downFiles []string

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		name := entry.Name()
		if strings.HasSuffix(name, ".up.sql") {
			upFiles = append(upFiles, name)
		} else if strings.HasSuffix(name, ".down.sql") {
			downFiles = append(downFiles, name)
		}
	}

	if len(upFiles) == 0 {
		t.Error("expected at least one up migration file, found none")
	}
	if len(downFiles) == 0 {
		t.Error("expected at least one down migration file, found none")
	}

	if len(upFiles) != len(downFiles) {
		t.Errorf("mismatched migration count: %d up files, %d down files", len(upFiles), len(downFiles))
	}

	// Verify up and down files match and are in numerical order
	for i := 0; i < len(upFiles); i++ {
		up := upFiles[i]
		partsUp := strings.Split(up, "_")
		if len(partsUp) < 2 {
			t.Errorf("invalid up migration file name: %s", up)
			continue
		}
		versionUp, err := strconv.ParseInt(partsUp[0], 10, 64)
		if err != nil {
			t.Errorf("failed to parse up version from %s: %v", up, err)
		}

		if versionUp != int64(i+1) {
			t.Errorf("expected version %d for file %s, got %d", i+1, up, versionUp)
		}

		// Find corresponding down file
		var foundDown bool
		for _, down := range downFiles {
			if strings.Split(down, "_")[0] == partsUp[0] {
				foundDown = true
				break
			}
		}
		if !foundDown {
			t.Errorf("missing corresponding down migration for: %s", up)
		}
	}
}

func TestMigrationStatementsAreNamed(t *testing.T) {
	// Check if migrate.go FS variable is populated
	entries, err := migrationsFS.ReadDir("migrations")
	if err != nil {
		t.Fatalf("failed to read migrations: %v", err)
	}
	if len(entries) == 0 {
		t.Error("migrations FS has no entries")
	}
}

func TestLiveAuditEventsMigrationPairing(t *testing.T) {
	up, err := migrationsFS.ReadFile("migrations/000004_live_audit_events.up.sql")
	if err != nil {
		t.Fatalf("failed to read 000004 up migration: %v", err)
	}
	down, err := migrationsFS.ReadFile("migrations/000004_live_audit_events.down.sql")
	if err != nil {
		t.Fatalf("failed to read 000004 down migration: %v", err)
	}
	for _, col := range []string{"event_id", "account_id", "event_type", "payload", "created_at"} {
		if !strings.Contains(string(up), col) {
			t.Errorf("000004 up migration missing column %q", col)
		}
	}
	if !strings.Contains(string(down), "live_audit_events") {
		t.Error("000004 down migration must drop live_audit_events table")
	}
}

func TestAnalysisResultColumnsAddedInVersionedMigration(t *testing.T) {
	// The analysis result columns must arrive through the v2 migration so databases
	// already at version 1 receive them, rather than being edited into 000001.
	content, err := migrationsFS.ReadFile("migrations/000002_backtest_analysis_results.up.sql")
	if err != nil {
		t.Fatalf("failed to read 000002 up migration: %v", err)
	}
	up := string(content)
	for _, column := range []string{"total_return", "trade_count", "equity_curve"} {
		if !strings.Contains(up, column) {
			t.Errorf("000002 up migration missing column %q", column)
		}
	}

	// The originally applied 000001 migration must not carry the analysis columns.
	backbone, err := migrationsFS.ReadFile("migrations/000001_worker_backbone.up.sql")
	if err != nil {
		t.Fatalf("failed to read 000001 up migration: %v", err)
	}
	for _, column := range []string{"total_return", "trade_count", "equity_curve"} {
		if strings.Contains(string(backbone), column) {
			t.Errorf("000001 up migration should not contain analysis column %q", column)
		}
	}
}

func TestMarketDataSchemaKeepsBarsNormalized(t *testing.T) {
	// Backtest input bars must persist normalized OHLCV fields only. Provider raw
	// payloads can be decoded upstream, but the bars table/query contract must not
	// grow a default raw JSON payload column.
	backbone, err := migrationsFS.ReadFile("migrations/000001_worker_backbone.up.sql")
	if err != nil {
		t.Fatalf("failed to read 000001 up migration: %v", err)
	}
	queries, err := os.ReadFile("queries/queries.sql")
	if err != nil {
		t.Fatalf("failed to read queries.sql: %v", err)
	}
	schema := string(backbone)
	queryText := string(queries)
	for _, required := range []string{"instrument_id", "timeframe", "timestamp", "open", "high", "low", "close", "volume"} {
		if !strings.Contains(schema, required) {
			t.Errorf("bars schema missing normalized column %q", required)
		}
		if !strings.Contains(queryText, required) {
			t.Errorf("bars queries missing normalized column %q", required)
		}
	}
	for _, forbidden := range []string{"raw_payload", "raw_response", "provider_payload"} {
		if strings.Contains(schema, forbidden) {
			t.Errorf("bars schema must not include raw provider payload column %q", forbidden)
		}
		if strings.Contains(queryText, forbidden) {
			t.Errorf("bars queries must not include raw provider payload column %q", forbidden)
		}
	}
}
