package services

// Live-DB tests for Slice F section service additions (Create + Delete
// + Reorder). Gated on TEST_DATABASE_URL, mirroring Slice A's pattern.

import (
	"context"
	"os"
	"testing"

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

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

func TestSectionService_SliceF(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()

	bases := NewBaseService(pool)
	sections := NewSectionService(pool)

	// Seed user + draft so we have a draft_id to attach sections to.
	userID := uuid.New()
	cleanup := func() {
		pool.ExecContext(ctx, `DELETE FROM paliad.submission_sections WHERE draft_id IN (SELECT id FROM paliad.submission_drafts WHERE user_id = $1)`, userID)
		pool.ExecContext(ctx, `DELETE FROM paliad.submission_drafts   WHERE user_id = $1`, userID)
		pool.ExecContext(ctx, `DELETE FROM paliad.users               WHERE id = $1`, userID)
		pool.ExecContext(ctx, `DELETE FROM auth.users                 WHERE id = $1`, userID)
	}
	cleanup()
	defer cleanup()

	email := "slice-f-" + userID.String()[:8] + "@hlc.com"
	if _, err := pool.ExecContext(ctx, `INSERT INTO auth.users (id, email) VALUES ($1, $2)`, userID, email); err != nil {
		t.Fatalf("seed auth.users: %v", err)
	}
	if _, err := pool.ExecContext(ctx,
		`INSERT INTO paliad.users (id, email, display_name, office, global_role, lang)
		 VALUES ($1, $2, 'Slice F User', 'munich', 'standard', 'de')`,
		userID, email); err != nil {
		t.Fatalf("seed paliad.users: %v", err)
	}
	users := NewUserService(pool)
	projects := NewProjectService(pool, users)
	parties := NewPartyService(pool, projects)
	vars := NewSubmissionVarsService(pool, projects, parties, users)
	renderer := NewSubmissionRenderer()
	drafts := NewSubmissionDraftService(pool, projects, vars, renderer)
	drafts.AttachComposer(bases, sections, "HLC")

	d, err := drafts.Create(ctx, userID, nil, "de.inf.lg.erwidg", "de")
	if err != nil {
		t.Fatalf("Create draft: %v", err)
	}
	initial, err := sections.ListForDraft(ctx, d.ID)
	if err != nil {
		t.Fatalf("ListForDraft initial: %v", err)
	}
	if len(initial) != 10 {
		t.Fatalf("expected 10 seeded sections; got %d", len(initial))
	}

	t.Run("Create custom section", func(t *testing.T) {
		created, err := sections.Create(ctx, SectionCreateInput{
			DraftID:    d.ID,
			SectionKey: "berufungsantraege",
			Kind:       "requests",
			LabelDE:    "Berufungsanträge",
			LabelEN:    "Appeal requests",
			Included:   true,
		})
		if err != nil {
			t.Fatalf("Create: %v", err)
		}
		if created.OrderIndex <= 10 {
			t.Errorf("auto-assigned order_index should be > existing max; got %d", created.OrderIndex)
		}
		// Slug collision must surface as ErrInvalidInput.
		_, err = sections.Create(ctx, SectionCreateInput{
			DraftID: d.ID, SectionKey: "berufungsantraege",
			Kind: "prose", LabelDE: "x", LabelEN: "x", Included: true,
		})
		if err == nil {
			t.Errorf("expected unique-key collision error; got nil")
		}
	})

	t.Run("Delete section", func(t *testing.T) {
		// Grab one of the seeded rows to delete.
		current, _ := sections.ListForDraft(ctx, d.ID)
		var victimID uuid.UUID
		for _, s := range current {
			if s.SectionKey == "exhibits" {
				victimID = s.ID
				break
			}
		}
		if victimID == uuid.Nil {
			t.Fatalf("expected exhibits section to exist")
		}
		if err := sections.Delete(ctx, victimID); err != nil {
			t.Fatalf("Delete: %v", err)
		}
		// Second delete returns not-found.
		if err := sections.Delete(ctx, victimID); err == nil {
			t.Errorf("expected ErrSubmissionSectionNotFound on second delete")
		}
	})

	t.Run("Reorder sections", func(t *testing.T) {
		current, _ := sections.ListForDraft(ctx, d.ID)
		if len(current) < 3 {
			t.Skipf("need at least 3 sections to test reorder; got %d", len(current))
		}
		// Reverse the order list.
		ids := make([]uuid.UUID, 0, len(current))
		for i := len(current) - 1; i >= 0; i-- {
			ids = append(ids, current[i].ID)
		}
		reordered, err := sections.Reorder(ctx, d.ID, ids)
		if err != nil {
			t.Fatalf("Reorder: %v", err)
		}
		// Verify the first ID in our list now has the lowest order_index.
		if reordered[0].ID != ids[0] {
			t.Errorf("first ID after reorder = %s; want %s", reordered[0].ID, ids[0])
		}
		// Order indices should be ascending.
		prev := 0
		for _, s := range reordered {
			if s.OrderIndex <= prev {
				t.Errorf("non-ascending order_index after reorder: %d (prev=%d) at %s", s.OrderIndex, prev, s.SectionKey)
			}
			prev = s.OrderIndex
		}
	})
}
