package services

// Live-DB integration tests for PgTemplateStore (t-paliad-349 slice 4).
// Skipped when TEST_DATABASE_URL is unset, mirroring the other live-DB
// tests. Exercises the full round-trip: Create (version 1) → Get →
// GetVersion → AddVersion (version 2, current re-pointed) → List, asserting
// the carrier bytes, stylemap, and slots persist and resolve intact.

import (
	"bytes"
	"context"
	"errors"
	"os"
	"testing"

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

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

func TestPgTemplateStore_RoundTrip(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()
	store := NewPgTemplateStore(pool)
	author := uuid.NewString()

	carrierV1 := []byte("PK\x03\x04 fake docx carrier v1")
	tmpl, err := store.Create(ctx,
		docforge.TemplateMetaInput{
			NameDE:    "Test-Vorlage",
			NameEN:    "Test template",
			Firm:      "HLC",
			CreatedBy: author,
		},
		docforge.TemplateVersionInput{
			CarrierBytes: carrierV1,
			Stylemap:     map[string]string{"paragraph": "Normal", "heading_1": "Heading 1"},
			Slots: []docforge.TemplateSlot{
				{Key: "project.case_number", Anchor: "{{project.case_number}}", Label: "Aktenzeichen", OrderIndex: 0},
				{Key: "parties.claimant.0.name", Anchor: "{{parties.claimant.0.name}}", OrderIndex: 1},
			},
			CreatedBy: author,
		})
	if err != nil {
		t.Fatalf("Create: %v", err)
	}
	// Clean up the row (cascades to versions + slots) regardless of outcome.
	defer func() {
		_, _ = pool.ExecContext(ctx, `DELETE FROM paliad.templates WHERE id = $1`, tmpl.ID)
	}()

	// --- Create assertions: version 1, defaults applied, content intact.
	if tmpl.Version != 1 {
		t.Errorf("Create version = %d; want 1", tmpl.Version)
	}
	if tmpl.Kind != "submission" || tmpl.SourceFormat != "docx" {
		t.Errorf("defaults: kind=%q format=%q; want submission/docx", tmpl.Kind, tmpl.SourceFormat)
	}
	if !bytes.Equal(tmpl.CarrierBytes, carrierV1) {
		t.Errorf("carrier round-trip mismatch: got %q", tmpl.CarrierBytes)
	}
	if tmpl.Stylemap["heading_1"] != "Heading 1" {
		t.Errorf("stylemap[heading_1] = %q; want 'Heading 1'", tmpl.Stylemap["heading_1"])
	}
	if len(tmpl.Slots) != 2 {
		t.Fatalf("len(slots) = %d; want 2", len(tmpl.Slots))
	}
	if tmpl.Slots[0].Key != "project.case_number" || tmpl.Slots[0].Label != "Aktenzeichen" {
		t.Errorf("slot[0] = %+v; want project.case_number/Aktenzeichen", tmpl.Slots[0])
	}

	// --- Get by template id resolves the current version.
	got, err := store.Get(ctx, tmpl.ID)
	if err != nil {
		t.Fatalf("Get: %v", err)
	}
	if got.Version != 1 || !bytes.Equal(got.CarrierBytes, carrierV1) || len(got.Slots) != 2 {
		t.Errorf("Get current version mismatch: v=%d slots=%d", got.Version, len(got.Slots))
	}

	// --- AddVersion bumps to 2 and re-points current.
	carrierV2 := []byte("PK\x03\x04 fake docx carrier v2 edited")
	v2, err := store.AddVersion(ctx, tmpl.ID, docforge.TemplateVersionInput{
		CarrierBytes: carrierV2,
		Stylemap:     map[string]string{"paragraph": "HLpat-Body-B0"},
		Slots:        []docforge.TemplateSlot{{Key: "today", Anchor: "{{today}}", OrderIndex: 0}},
		CreatedBy:    author,
	})
	if err != nil {
		t.Fatalf("AddVersion: %v", err)
	}
	if v2.Version != 2 {
		t.Errorf("AddVersion version = %d; want 2", v2.Version)
	}
	if !bytes.Equal(v2.CarrierBytes, carrierV2) || len(v2.Slots) != 1 || v2.Slots[0].Key != "today" {
		t.Errorf("AddVersion content mismatch: carrier/slots wrong")
	}

	// Get now resolves version 2 (current re-pointed).
	cur, err := store.Get(ctx, tmpl.ID)
	if err != nil {
		t.Fatalf("Get after AddVersion: %v", err)
	}
	if cur.Version != 2 || !bytes.Equal(cur.CarrierBytes, carrierV2) {
		t.Errorf("Get after AddVersion = v%d; want v2 with new carrier", cur.Version)
	}

	// --- List reflects the current version number, filtered by firm.
	metas, err := store.List(ctx, docforge.TemplateFilter{Firm: "HLC", ActiveOnly: true})
	if err != nil {
		t.Fatalf("List: %v", err)
	}
	var found *docforge.TemplateMeta
	for i := range metas {
		if metas[i].ID == tmpl.ID {
			found = &metas[i]
			break
		}
	}
	if found == nil {
		t.Fatalf("List did not return the created template")
	}
	if found.Version != 2 {
		t.Errorf("List version = %d; want 2 (current)", found.Version)
	}

	// --- Unknown id → ErrTemplateNotFound.
	if _, err := store.Get(ctx, uuid.NewString()); !errors.Is(err, docforge.ErrTemplateNotFound) {
		t.Errorf("Get(unknown) err = %v; want ErrTemplateNotFound", err)
	}
}
