package parlament

import (
	"testing"
)

// These tests hit the live parlament.gv.at API.
// Run with: go test ./cmd/party/parlament/ -v
// Skip with: go test -short

func newTestClient(t *testing.T) *Client {
	t.Helper()
	if testing.Short() {
		t.Skip("skipping live API test in short mode")
	}
	return NewClient()
}

// assertNonEmpty fails if any session has a blank field.
func assertSessionsPopulated(t *testing.T, sessions []Session) {
	t.Helper()
	for i, s := range sessions {
		if s.Date == "" {
			t.Errorf("session[%d] missing Date", i)
		}
		if s.Title == "" {
			t.Errorf("session[%d] missing Title", i)
		}
		if s.Path == "" {
			t.Errorf("session[%d] missing Path", i)
		}
	}
}

func TestListSessions(t *testing.T) {
	c := newTestClient(t)

	sessions, total, err := c.ListSessions(SessionFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
	})
	if err != nil {
		t.Fatalf("ListSessions: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one session, got 0")
	}
	if len(sessions) == 0 {
		t.Fatal("expected rows, got none")
	}

	assertSessionsPopulated(t, sessions)

	t.Logf("total=%d rows=%d", total, len(sessions))
	for i, s := range sessions {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", s.Date, s.Title, s.Path)
	}
}

func TestListSessions_TotalMatchesRows(t *testing.T) {
	c := newTestClient(t)

	sessions, total, err := c.ListSessions(SessionFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
	})
	if err != nil {
		t.Fatalf("ListSessions: %v", err)
	}
	if total != len(sessions) {
		t.Errorf("total=%d but got %d rows (showAll=true should return everything)", total, len(sessions))
	}
}

func TestListSessions_BothChambers(t *testing.T) {
	c := newTestClient(t)

	nr, nrTotal, err := c.ListSessions(SessionFilter{Chamber: []string{"NR"}, Period: []string{"XXVIII"}})
	if err != nil {
		t.Fatalf("NR: %v", err)
	}
	br, brTotal, err := c.ListSessions(SessionFilter{Chamber: []string{"BR"}, Period: []string{"XXVIII"}})
	if err != nil {
		t.Fatalf("BR: %v", err)
	}

	assertSessionsPopulated(t, nr)
	assertSessionsPopulated(t, br)

	t.Logf("NR sessions: %d, BR sessions: %d", nrTotal, brTotal)
	if nrTotal == 0 || brTotal == 0 {
		t.Error("expected results for both chambers")
	}
}

func TestListSessions_PeriodFilter(t *testing.T) {
	c := newTestClient(t)

	_, xxvii, err := c.ListSessions(SessionFilter{Chamber: []string{"NR"}, Period: []string{"XXVII"}})
	if err != nil {
		t.Fatalf("XXVII: %v", err)
	}
	_, xxviii, err := c.ListSessions(SessionFilter{Chamber: []string{"NR"}, Period: []string{"XXVIII"}})
	if err != nil {
		t.Fatalf("XXVIII: %v", err)
	}

	// XXVII was a full 5-year term; XXVIII is still in progress — XXVII should have more
	t.Logf("XXVII=%d XXVIII=%d", xxvii, xxviii)
	if xxvii <= xxviii {
		t.Errorf("expected XXVII (%d) to have more sessions than ongoing XXVIII (%d)", xxvii, xxviii)
	}
}

func TestListParliamentarians(t *testing.T) {
	c := newTestClient(t)

	mps, total, err := c.ListParliamentarians(ParliamentarianFilter{
		Period: []string{"XXVIII"},
	})
	if err != nil {
		t.Fatalf("ListParliamentarians: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one MP, got 0")
	}

	t.Logf("total=%d rows=%d", total, len(mps))
	for i, mp := range mps {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", mp.Name, mp.Faction, mp.Constituency)
	}

	for i, mp := range mps {
		if mp.Name == "" {
			t.Errorf("mp[%d] missing Name", i)
		}
		if mp.Path == "" {
			t.Errorf("mp[%d] missing Path", i)
		}
	}
}

func TestGetDetail_Parliamentarian(t *testing.T) {
	c := newTestClient(t)

	mps, _, err := c.ListParliamentarians(ParliamentarianFilter{})
	if err != nil || len(mps) == 0 {
		t.Fatalf("ListParliamentarians: %v", err)
	}

	// Find the first MP with a valid path.
	var path string
	for _, mp := range mps {
		if mp.Path != "" {
			path = mp.Path
			break
		}
	}
	if path == "" {
		t.Fatal("no MP has a Path")
	}

	detail, err := c.GetDetail(path)
	if err != nil {
		t.Fatalf("GetDetail(%q): %v", path, err)
	}
	for _, key := range []string{"meta", "pagetype", "content"} {
		if _, ok := detail[key]; !ok {
			t.Errorf("detail missing key %q", key)
		}
	}
	t.Logf("path: %s", path)
}

func TestListDocuments_Resolutions(t *testing.T) {
	c := newTestClient(t)

	docs, total, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
		Type:    DocResolution,
	})
	if err != nil {
		t.Fatalf("ListDocuments(resolutions): %v", err)
	}

	if total == 0 {
		t.Fatal("expected at least one resolution")
	}
	t.Logf("total=%d rows=%d", total, len(docs))
	for i, d := range docs {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", d.Date, d.Number, d.Title)
	}

	for i, d := range docs {
		if d.Date == "" {
			t.Errorf("doc[%d] missing Date", i)
		}
		if d.Number == "" {
			t.Errorf("doc[%d] missing Number", i)
		}
		if d.Path == "" {
			t.Errorf("doc[%d] missing Path", i)
		}
	}
}

func TestListDocuments_Motions(t *testing.T) {
	c := newTestClient(t)

	docs, total, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
		Type:    DocMotion,
	})
	if err != nil {
		t.Fatalf("ListDocuments(motions): %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one motion")
	}
	t.Logf("total=%d rows=%d", total, len(docs))
	for i, d := range docs {
		if i >= 3 {
			break
		}
		t.Logf("  %s | %s | %s", d.Date, d.Number, d.Title)
	}
}

func TestListDocuments_GovBills(t *testing.T) {
	c := newTestClient(t)

	docs, total, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
		Type:    DocGovBill,
	})
	if err != nil {
		t.Fatalf("ListDocuments(gov bills): %v", err)
	}

	t.Logf("total=%d rows=%d", total, len(docs))
	for i, d := range docs {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", d.Date, d.Number, d.Title)
	}
}

func TestListProtocols(t *testing.T) {
	c := newTestClient(t)

	protocols, total, err := c.ListProtocols(ProtocolFilter{
		Chamber: []string{"NRSITZ"},
		Period:  []string{"XXVIII"},
	})
	if err != nil {
		t.Fatalf("ListProtocols: %v", err)
	}

	if total == 0 {
		t.Fatal("expected at least one protocol")
	}
	t.Logf("total=%d rows=%d", total, len(protocols))
	for i, p := range protocols {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", p.Date, p.Session, p.Path)
	}

	for i, p := range protocols {
		if p.Date == "" {
			t.Errorf("protocol[%d] missing Date", i)
		}
		if p.Session == "" {
			t.Errorf("protocol[%d] missing Session", i)
		}
		if p.Path == "" {
			t.Errorf("protocol[%d] missing Path", i)
		}
	}
}

func TestGetDetail_Document(t *testing.T) {
	c := newTestClient(t)

	docs, _, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
		Type:    DocResolution,
	})
	if err != nil || len(docs) == 0 {
		t.Fatalf("ListDocuments: %v", err)
	}

	first := docs[0]
	if first.Path == "" {
		t.Skip("document has no path, skipping detail fetch")
	}

	detail, err := c.GetDetail(first.Path)
	if err != nil {
		t.Fatalf("GetDetail(%q): %v", first.Path, err)
	}

	for _, key := range []string{"meta", "pagetype", "content"} {
		if _, ok := detail[key]; !ok {
			t.Errorf("detail missing key %q", key)
		}
	}
	t.Logf("path: %s", first.Path)
}

func TestListDocuments_CitizenInitiatives(t *testing.T) {
	c := newTestClient(t)

	docs, total, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Type:    DocCitizenInitiative,
	})
	if err != nil {
		t.Fatalf("ListDocuments(citizen initiatives): %v", err)
	}
	t.Logf("total=%d rows=%d", total, len(docs))
	if total == 0 {
		t.Fatal("expected at least one citizen initiative")
	}
	for i, d := range docs {
		if i >= 3 {
			break
		}
		t.Logf("  %s | %s | %s", d.Date, d.Number, d.Title)
	}
}

func TestListDocuments_WrittenQuestions(t *testing.T) {
	c := newTestClient(t)

	docs, total, err := c.ListDocuments(DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
		Type:    DocWrittenQuestion,
	})
	if err != nil {
		t.Fatalf("ListDocuments(written questions): %v", err)
	}
	t.Logf("total=%d rows=%d", total, len(docs))
}

func TestListEvents(t *testing.T) {
	c := newTestClient(t)

	events, total, err := c.ListEvents(EventFilter{
		DateFrom: "2025-01-01",
		DateTo:   "2025-03-31",
	})
	if err != nil {
		t.Fatalf("ListEvents: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one event")
	}
	if len(events) == 0 {
		t.Fatal("expected rows")
	}

	t.Logf("total=%d rows=%d", total, len(events))
	for i, e := range events {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s | %s", e.Date, e.Type, e.Body, e.Title)
	}

	for i, e := range events {
		if e.Date == "" {
			t.Errorf("event[%d] missing Date", i)
		}
		if e.Title == "" {
			t.Errorf("event[%d] missing Title", i)
		}
	}
}

func TestListEvents_ByBody(t *testing.T) {
	c := newTestClient(t)

	events, total, err := c.ListEvents(EventFilter{
		Body:     []string{"Nationalrat"},
		DateFrom: "2025-01-01",
		DateTo:   "2025-12-31",
	})
	if err != nil {
		t.Fatalf("ListEvents(Nationalrat): %v", err)
	}
	t.Logf("Nationalrat events in 2025: %d", total)
	if total == 0 {
		t.Fatal("expected Nationalrat events")
	}
	for _, e := range events {
		if e.Body != "Nationalrat" {
			t.Errorf("expected Body=Nationalrat, got %q", e.Body)
			break
		}
	}
}

func TestListGovernmentMembers(t *testing.T) {
	c := newTestClient(t)

	members, total, err := c.ListGovernmentMembers(GovernmentMemberFilter{})
	if err != nil {
		t.Fatalf("ListGovernmentMembers: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one government member")
	}

	t.Logf("total=%d rows=%d", total, len(members))
	for i, m := range members {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", m.Name, m.RoleShort, m.Party)
	}

	for i, m := range members {
		if m.Name == "" {
			t.Errorf("member[%d] missing Name", i)
		}
	}
}

func TestListGovernmentMembers_Active(t *testing.T) {
	c := newTestClient(t)

	_, allTotal, err := c.ListGovernmentMembers(GovernmentMemberFilter{})
	if err != nil {
		t.Fatalf("all: %v", err)
	}
	active, activeTotal, err := c.ListGovernmentMembers(GovernmentMemberFilter{Active: true})
	if err != nil {
		t.Fatalf("active: %v", err)
	}

	t.Logf("all=%d active=%d", allTotal, activeTotal)
	if activeTotal == 0 {
		t.Fatal("expected active government members")
	}
	if activeTotal >= allTotal {
		t.Errorf("active (%d) should be fewer than all (%d)", activeTotal, allTotal)
	}
	for i, m := range active {
		if !m.Active {
			t.Errorf("active[%d] %q has Active=false", i, m.Name)
		}
	}
}

func TestListPressReleases(t *testing.T) {
	c := newTestClient(t)

	releases, total, err := c.ListPressReleases(PressReleaseFilter{
		Year: []string{"2025"},
	})
	if err != nil {
		t.Fatalf("ListPressReleases: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one press release")
	}

	t.Logf("total=%d rows=%d", total, len(releases))
	for i, r := range releases {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s", r.Date, r.Number, r.Title)
	}

	for i, r := range releases {
		if r.Date == "" {
			t.Errorf("release[%d] missing Date", i)
		}
		if r.Title == "" {
			t.Errorf("release[%d] missing Title", i)
		}
		if r.Path == "" {
			t.Errorf("release[%d] missing Path", i)
		}
	}
}

func TestListCommitteeMemberships(t *testing.T) {
	c := newTestClient(t)

	memberships, total, err := c.ListCommitteeMemberships(CommitteeMembershipFilter{
		Period:  []string{"XXVIII"},
		Chamber: []string{"NR"},
	})
	if err != nil {
		t.Fatalf("ListCommitteeMemberships: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one membership")
	}

	t.Logf("total=%d rows=%d", total, len(memberships))
	for i, m := range memberships {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s | %s", m.Period, m.Role, m.Committee, m.PersonID)
	}

	for i, m := range memberships {
		if m.Committee == "" {
			t.Errorf("membership[%d] missing Committee", i)
		}
		if m.PersonID == "" {
			t.Errorf("membership[%d] missing PersonID", i)
		}
	}
}

func TestListCommitteeMemberships_ByPerson(t *testing.T) {
	c := newTestClient(t)

	// Get one MP's PAD_INTERN and check their committee memberships.
	mps, _, err := c.ListParliamentarians(ParliamentarianFilter{Period: []string{"XXVIII"}})
	if err != nil || len(mps) == 0 {
		t.Fatalf("ListParliamentarians: %v", err)
	}

	memberships, _, err := c.ListCommitteeMemberships(CommitteeMembershipFilter{
		Period: []string{"XXVIII"},
	})
	if err != nil || len(memberships) == 0 {
		t.Fatalf("ListCommitteeMemberships: %v", err)
	}

	// Look up the first known PersonID and filter to just that person.
	personID := memberships[0].PersonID
	byPerson, total, err := c.ListCommitteeMemberships(CommitteeMembershipFilter{
		Period:   []string{"XXVIII"},
		PersonID: []string{personID},
	})
	if err != nil {
		t.Fatalf("ListCommitteeMemberships(person %s): %v", personID, err)
	}
	t.Logf("personID=%s committees=%d", personID, total)
	for _, m := range byPerson {
		if m.PersonID != personID {
			t.Errorf("unexpected PersonID %q (want %q)", m.PersonID, personID)
		}
	}
}

func TestListParticipatoryItems(t *testing.T) {
	c := newTestClient(t)

	items, total, err := c.ListParticipatoryItems(ParticipatoryFilter{
		Active: true,
	})
	if err != nil {
		t.Fatalf("ListParticipatoryItems: %v", err)
	}
	if total == 0 {
		t.Fatal("expected at least one active participatory item")
	}

	t.Logf("total=%d rows=%d", total, len(items))
	for i, it := range items {
		if i >= 5 {
			break
		}
		t.Logf("  %s | %s | %s | supporters=%s", it.Date, it.Type, it.Number, it.Supporters)
	}

	for i, it := range items {
		if !it.Active {
			t.Errorf("item[%d] %q has Active=false despite AKTIV=J filter", i, it.Number)
		}
		if it.Title == "" {
			t.Errorf("item[%d] missing Title", i)
		}
	}
}

func TestListParticipatoryItems_ByPeriod(t *testing.T) {
	c := newTestClient(t)

	items, total, err := c.ListParticipatoryItems(ParticipatoryFilter{
		Period: []string{"XXVIII"},
	})
	if err != nil {
		t.Fatalf("ListParticipatoryItems(XXVIII): %v", err)
	}
	t.Logf("XXVIII participatory items: %d", total)
	if total == 0 {
		t.Fatal("expected participatory items for XXVIII")
	}
	for i, it := range items {
		if i >= 3 {
			break
		}
		t.Logf("  %s | %s | %s", it.Date, it.Category, it.Title)
	}
}

func TestGetDetail(t *testing.T) {
	c := newTestClient(t)

	// Fetch the latest session from ListSessions and get its detail page.
	sessions, _, err := c.ListSessions(SessionFilter{
		Chamber: []string{"NR"},
		Period:  []string{"XXVIII"},
	})
	if err != nil || len(sessions) == 0 {
		t.Fatalf("ListSessions: %v", err)
	}

	latest := sessions[0]
	if latest.Path == "" {
		t.Fatalf("session has no path: %+v", latest)
	}

	detail, err := c.GetDetail(latest.Path)
	if err != nil {
		t.Fatalf("GetDetail(%q): %v", latest.Path, err)
	}
	if len(detail) == 0 {
		t.Fatal("expected non-empty detail map")
	}

	t.Logf("path: %s", latest.Path)
	ks := make([]string, 0, len(detail))
	for k := range detail {
		ks = append(ks, k)
	}
	t.Logf("top-level keys: %v", ks)
}
