package app

import (
	"context"
	"errors"
	"os"
	"path/filepath"
	"testing"

	"github.com/dtoro/oikos/internal/core/ports/portstest"
)

func writeSeedFile(t *testing.T, dir, name, content string) {
	t.Helper()
	if err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0644); err != nil {
		t.Fatal(err)
	}
}

func TestSeedServiceIngestOrder(t *testing.T) {
	dir := t.TempDir()
	writeSeedFile(t, dir, "ontology.yaml", "a: 1")
	writeSeedFile(t, dir, "inventory.yaml", "b: 2")
	writeSeedFile(t, dir, "policy.yaml", "c: 3")
	writeSeedFile(t, dir, "knowledge.yaml", "d: 4")

	repo := portstest.NewSeedRepo()
	if err := NewSeedService(repo).Ingest(context.Background(), dir); err != nil {
		t.Fatalf("Ingest: %v", err)
	}

	want := []string{"ontology.yaml", "inventory.yaml", "policy.yaml", "knowledge.yaml"}
	if len(repo.Order) != len(want) {
		t.Fatalf("ingested %v, want %v", repo.Order, want)
	}
	for i, f := range want {
		if repo.Order[i] != f {
			t.Errorf("order[%d] = %s, want %s", i, repo.Order[i], f)
		}
	}
}

func TestSeedServiceKnowledgeOptional(t *testing.T) {
	dir := t.TempDir()
	writeSeedFile(t, dir, "ontology.yaml", "a: 1")
	writeSeedFile(t, dir, "inventory.yaml", "b: 2")
	writeSeedFile(t, dir, "policy.yaml", "c: 3")

	repo := portstest.NewSeedRepo()
	if err := NewSeedService(repo).Ingest(context.Background(), dir); err != nil {
		t.Fatalf("Ingest without knowledge seed: %v", err)
	}
	for _, f := range repo.Order {
		if f == "knowledge.yaml" {
			t.Error("knowledge.yaml must be skipped when absent")
		}
	}
}

func TestSeedServiceMissingStructuralSeedFails(t *testing.T) {
	dir := t.TempDir()
	writeSeedFile(t, dir, "ontology.yaml", "a: 1")
	// inventory.yaml and policy.yaml absent — both are required.

	repo := portstest.NewSeedRepo()
	err := NewSeedService(repo).Ingest(context.Background(), dir)
	if err == nil {
		t.Fatal("missing inventory seed must fail the ingest")
	}
	if repo.Order[len(repo.Order)-1] != "ontology.yaml" {
		t.Errorf("ingest stopped at %v, want ontology.yaml only", repo.Order)
	}
}

func TestSeedServiceIngestErrorPropagates(t *testing.T) {
	dir := t.TempDir()
	writeSeedFile(t, dir, "ontology.yaml", "a: 1")
	writeSeedFile(t, dir, "inventory.yaml", "b: 2")

	repo := portstest.NewSeedRepo()
	repo.IngestErr["inventory.yaml"] = errors.New("entity bad: unknown type")
	err := NewSeedService(repo).Ingest(context.Background(), dir)
	if err == nil || !errors.Is(err, repo.IngestErr["inventory.yaml"]) {
		t.Fatalf("got %v, want ingest error", err)
	}
}

func TestSeedServiceExport(t *testing.T) {
	repo := portstest.NewSeedRepo()
	repo.ExportFiles = map[string][]byte{"ontology.yaml": []byte("x")}
	files, err := NewSeedService(repo).Export(context.Background())
	if err != nil {
		t.Fatalf("Export: %v", err)
	}
	if string(files["ontology.yaml"]) != "x" {
		t.Errorf("export = %v", files)
	}
}
