package services

import (
	"context"
	"os"
	"testing"

	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"

	"mgit.msbls.de/m/paliad/internal/db"
)

// TestListProceedings covers the proceeding chip-pool query that powers
// the Fristenrechner overhaul Mode A "Verfahren" filter strip (S3,
// design §3.1). The legacy callers go through ListFristenrechnerTypes
// (no filters) — that path stays green here. The new ListProceedings
// API accepts Jurisdiction + Kind filters; the Kind filter requires
// mig 153 to have landed, so this test skips the Kind=proceeding case
// when the column doesn't yet exist.
func TestListProceedings(t *testing.T) {
	url := os.Getenv("TEST_DATABASE_URL")
	if url == "" {
		t.Skip("TEST_DATABASE_URL not set — skipping live DB test")
	}
	if err := db.ApplyMigrations(url); err != nil {
		t.Fatalf("apply migrations: %v", err)
	}
	pool, err := sqlx.Connect("postgres", url)
	if err != nil {
		t.Fatalf("connect: %v", err)
	}
	defer pool.Close()
	ctx := context.Background()

	rules := NewDeadlineRuleService(pool)
	holidays := NewHolidayService(pool)
	courts := NewCourtService(pool)
	fr := NewFristenrechnerService(rules, holidays, courts)

	t.Run("no filters returns the legacy fristenrechner set", func(t *testing.T) {
		got, err := fr.ListProceedings(ctx, ProceedingListOptions{})
		if err != nil {
			t.Fatalf("list proceedings: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected non-empty proceeding list")
		}
		// Sanity — upc.inf.cfi should always be in the active set.
		found := false
		for _, p := range got {
			if p.Code == "upc.inf.cfi" {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("upc.inf.cfi not in proceedings list")
		}
	})

	t.Run("jurisdiction=UPC narrows to UPC-only", func(t *testing.T) {
		got, err := fr.ListProceedings(ctx, ProceedingListOptions{Jurisdiction: "UPC"})
		if err != nil {
			t.Fatalf("list proceedings UPC: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected UPC proceedings")
		}
		for _, p := range got {
			if p.Group != "UPC" {
				t.Errorf("non-UPC proceeding leaked: %s (group=%q)", p.Code, p.Group)
			}
		}
	})

	t.Run("jurisdiction=DE returns DE proceedings", func(t *testing.T) {
		got, err := fr.ListProceedings(ctx, ProceedingListOptions{Jurisdiction: "DE"})
		if err != nil {
			t.Fatalf("list proceedings DE: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected DE proceedings")
		}
		for _, p := range got {
			if p.Group != "DE" {
				t.Errorf("non-DE proceeding leaked: %s (group=%q)", p.Code, p.Group)
			}
		}
	})

	t.Run("ListFristenrechnerTypes legacy alias still works", func(t *testing.T) {
		got, err := fr.ListFristenrechnerTypes(ctx)
		if err != nil {
			t.Fatalf("list fristenrechner types: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected non-empty types")
		}
	})

	t.Run("kind=proceeding narrows to primary proceedings only", func(t *testing.T) {
		got, err := fr.ListProceedings(ctx, ProceedingListOptions{Kind: "proceeding"})
		if err != nil {
			t.Fatalf("list proceedings kind=proceeding: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected non-empty primary-proceeding list")
		}
		// upc.inf.cfi is unambiguously a primary proceeding — must
		// survive the filter.
		found := false
		for _, p := range got {
			if p.Code == "upc.inf.cfi" {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("upc.inf.cfi missing from kind=proceeding list")
		}
		// upc.cfi.interim is the canonical phase row (per mig 153 +
		// taxonomy doc §0.4 Group B) — must NOT appear.
		for _, p := range got {
			if p.Code == "upc.cfi.interim" {
				t.Errorf("phase row upc.cfi.interim leaked into kind=proceeding")
			}
		}
	})

	t.Run("event_kind=filing narrows to proceedings with filing events", func(t *testing.T) {
		got, err := fr.ListProceedings(ctx, ProceedingListOptions{
			Jurisdiction: "UPC",
			Kind:         "proceeding",
			EventKind:    "filing",
		})
		if err != nil {
			t.Fatalf("list proceedings UPC+filing: %v", err)
		}
		if len(got) == 0 {
			t.Fatalf("expected UPC proceedings with filing events")
		}
		// upc.inf.cfi has at least one rule anchored on a filing event
		// (Klageerhebung, SoD, etc.) — must survive.
		found := false
		for _, p := range got {
			if p.Code == "upc.inf.cfi" {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("upc.inf.cfi missing from UPC + event_kind=filing list")
		}
	})
}
