package shared

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

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

func TestUnitRefUnmarshalAcceptsIntegerAndNumericString(t *testing.T) {
	var integerRef UnitRef
	if err := json.Unmarshal([]byte(`12`), &integerRef); err != nil {
		t.Fatalf("Unmarshal(integer) error = %v, want nil", err)
	}
	if got := integerRef.String(); got != "12" {
		t.Fatalf("integer ref = %q, want 12", got)
	}
	if got := integerRef.Int(); got != 12 {
		t.Fatalf("integer ref value = %d, want 12", got)
	}

	var stringRef UnitRef
	if err := json.Unmarshal([]byte(`"12"`), &stringRef); err != nil {
		t.Fatalf("Unmarshal(string) error = %v, want nil", err)
	}
	if got := stringRef.String(); got != "12" {
		t.Fatalf("string ref = %q, want 12", got)
	}
}

func TestUnitRefUnmarshalRejectsNonIntegerValues(t *testing.T) {
	for _, raw := range []string{`true`, `null`, `1.5`, `{}`, `"seg-001"`, `" 1 "`, `0`, `-1`} {
		t.Run(raw, func(t *testing.T) {
			var ref UnitRef
			err := json.Unmarshal([]byte(raw), &ref)
			if err == nil {
				t.Fatal("Unmarshal() error = nil, want error")
			}
		})
	}
}

func TestResolveUnitIDReturnsExistingIntegerSourceUnitID(t *testing.T) {
	doc := unitRefSourceDocument(2, 10)

	got, err := ResolveUnitID(source.NewDocumentIndex(doc), "start_unit_id", UnitRefFromInt(2))
	if err != nil {
		t.Fatalf("ResolveUnitID() error = %v, want nil", err)
	}
	if got != 2 {
		t.Fatalf("ResolveUnitID() = %d, want exact source unit ID", got)
	}
}

func TestResolveUnitIDDoesNotFallbackToOneBasedUnitNumber(t *testing.T) {
	doc := unitRefSourceDocument(10, 20)

	_, err := ResolveUnitID(source.NewDocumentIndex(doc), "end_unit_id", UnitRefFromInt(2))
	if err == nil {
		t.Fatal("ResolveUnitID() error = nil, want missing source-unit ID")
	}
}

func TestResolveUnitIDRejectsMissingUnit(t *testing.T) {
	doc := unitRefSourceDocument(1)

	_, err := ResolveUnitID(source.NewDocumentIndex(doc), "start_unit_id", UnitRefFromInt(9))
	if err == nil {
		t.Fatal("ResolveUnitID() error = nil, want error")
	}
	if !strings.Contains(err.Error(), "start_unit_id 9") {
		t.Fatalf("ResolveUnitID() error = %q, want field and value context", err.Error())
	}
}

func unitRefSourceDocument(ids ...int) *source.SourceDocument {
	doc := &source.SourceDocument{
		ID:     "session-alpha",
		Kind:   "transcript",
		Format: "application/json",
		Digest: "sha256:test",
	}
	for _, id := range ids {
		doc.Units = append(doc.Units, source.SourceUnit{
			ID:   id,
			Kind: "transcript_segment",
			Text: "text",
		})
	}
	return doc
}
