package main

import (
	"bytes"
	"encoding/json"
	"strings"
	"testing"

	"textmachine/backend/internal/pipeline"
)

// export_cli_test.go pins the tmctl surface of the read-only export projection (D39 слой 6): the
// parse of the `export` command + `--plaintext`, the default stable-JSON render, and the human
// plaintext render (banner + text, flagged chunks marked, dropped chunks empty).

func TestParseExportPlaintext(t *testing.T) {
	inv, err := parseInvocation([]string{"export", "--config", "b.yaml", "--plaintext"}, &bytes.Buffer{})
	if err != nil {
		t.Fatalf("export --plaintext must parse: %v", err)
	}
	if inv.cmd != "export" || inv.cfgPath != "b.yaml" || !inv.asPlaintext {
		t.Fatalf("inv = %+v", inv)
	}
	// Default (no flag) is JSON, not plaintext.
	inv2, err := parseInvocation([]string{"export", "--config", "b.yaml"}, &bytes.Buffer{})
	if err != nil || inv2.asPlaintext {
		t.Fatalf("export default must be JSON (asPlaintext=false): inv=%+v err=%v", inv2, err)
	}
}

func sampleExport() *pipeline.BookExport {
	return &pipeline.BookExport{BookID: "b1", Chunks: []pipeline.ChunkExport{
		{Chapter: 1, ChunkIdx: 0, SnapshotID: "snap", Disposition: "ok", FinalText: "Чистый текст."},
		{Chapter: 2, ChunkIdx: 0, SnapshotID: "snap", Disposition: "flagged", FlagReason: "sanitizer_stripped", FinalText: "Очищенный текст."},
		{Chapter: 3, ChunkIdx: 0, SnapshotID: "snap", Disposition: "flagged", FlagReason: "sanitizer_defect", FinalText: ""},
	}}
}

func TestRenderExportJSONIsStable(t *testing.T) {
	var b bytes.Buffer
	if err := renderExport(&b, sampleExport(), false); err != nil {
		t.Fatal(err)
	}
	// The default surface is valid JSON the polygon extractor can consume: it round-trips and carries
	// every chunk's export bytes and metadata.
	var got pipeline.BookExport
	if err := json.Unmarshal(b.Bytes(), &got); err != nil {
		t.Fatalf("export JSON must round-trip: %v\n%s", err, b.String())
	}
	if got.BookID != "b1" || len(got.Chunks) != 3 {
		t.Fatalf("round-tripped export = %+v", got)
	}
	if got.Chunks[1].FinalText != "Очищенный текст." || got.Chunks[1].FlagReason != "sanitizer_stripped" {
		t.Fatalf("stripped chunk lost fidelity: %+v", got.Chunks[1])
	}
}

func TestRenderExportPlaintextBanners(t *testing.T) {
	var b bytes.Buffer
	if err := renderExport(&b, sampleExport(), true); err != nil {
		t.Fatal(err)
	}
	out := b.String()
	for _, want := range []string{
		"=== ГЛАВА 1 ЧАНК 0 ===\nЧистый текст.",
		"=== ГЛАВА 2 ЧАНК 0 — flagged (sanitizer_stripped) (утечка вычищена, проверь) ===\nОчищенный текст.",
		"=== ГЛАВА 3 ЧАНК 0 — flagged (sanitizer_defect) (не переведён, помечен для человека) ===",
	} {
		if !strings.Contains(out, want) {
			t.Fatalf("plaintext export must contain %q, got:\n%s", want, out)
		}
	}
}
