package transcript

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

	"gitea.maximumdirect.net/eric/notarius/internal/core/source"
	"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
	"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
)

func TestNewReturnsAdapterWithKey(t *testing.T) {
	adapter := New()
	if adapter == nil {
		t.Fatal("New() = nil, want adapter")
	}
	if adapter.Key() != Key {
		t.Fatalf("adapter.Key() = %q, want %q", adapter.Key(), Key)
	}
}

func TestModuleSpec(t *testing.T) {
	got := ModuleSpec()
	want := pipeline.ModuleSpec{
		Key:            Key,
		Stage:          pipeline.StageInput,
		ExecutionClass: contracts.ExecutionClassDeterministic,
		Provides: []string{
			"source.transcript",
			"transcript.speaker",
			"transcript.timestamps",
		},
	}
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
	}

	got.Provides[0] = "changed"
	again := ModuleSpec()
	if !reflect.DeepEqual(again, want) {
		t.Fatalf("ModuleSpec() after caller mutation = %#v, want %#v", again, want)
	}
}

func TestRegisterMakesAdapterBuildable(t *testing.T) {
	registry := pipeline.NewInputAdapterRegistry()

	if err := Register(registry); err != nil {
		t.Fatalf("Register() error = %v, want nil", err)
	}

	adapter, err := registry.Build(Key)
	if err != nil {
		t.Fatalf("Build() error = %v, want nil", err)
	}
	if adapter.Key() != Key {
		t.Fatalf("adapter.Key() = %q, want %q", adapter.Key(), Key)
	}
	if err := registry.ValidateOptions(Key, map[string]any{"unexpected": true}); err == nil || !strings.Contains(err.Error(), "unknown option") {
		t.Fatalf("ValidateOptions() error = %v, want unknown option error", err)
	}
}

func TestRegisterStoresModuleSpec(t *testing.T) {
	registry := pipeline.NewInputAdapterRegistry()

	if err := Register(registry); err != nil {
		t.Fatalf("Register() error = %v, want nil", err)
	}

	got, ok := registry.Spec(Key)
	if !ok {
		t.Fatal("Spec() ok = false, want true")
	}
	want := ModuleSpec()
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("Spec() = %#v, want %#v", got, want)
	}
}

func TestRegisterNilRegistryReturnsError(t *testing.T) {
	err := Register(nil)
	if err == nil {
		t.Fatal("Register(nil) error = nil, want error")
	}
	if !strings.Contains(err.Error(), "input adapter registry") {
		t.Fatalf("Register(nil) error = %q, want registry context", err.Error())
	}
}

func TestMetadataHelpers(t *testing.T) {
	unit := source.SourceUnit{
		Metadata: map[string]any{
			MetadataSpeaker: "Narrator",
			MetadataStart:   json.Number("1.25"),
			MetadataEnd:     json.Number("2.5"),
		},
	}

	if got, ok := Speaker(unit); !ok || got != "Narrator" {
		t.Fatalf("Speaker() = %q, %v; want Narrator, true", got, ok)
	}
	if got, ok := Start(unit); !ok || got != json.Number("1.25") {
		t.Fatalf("Start() = %q, %v; want 1.25, true", got, ok)
	}
	if got, ok := End(unit); !ok || got != json.Number("2.5") {
		t.Fatalf("End() = %q, %v; want 2.5, true", got, ok)
	}
}
