package m2mcore_test

import (
	"context"
	"errors"
	"testing"

	"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2m"
	"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
)

func newTestDeal(t *testing.T) *m2mcore.Deal {
	t.Helper()
	guid, err := m2mcore.NewUUIDv4()
	if err != nil {
		t.Fatalf("UUID: %v", err)
	}
	d, err := m2mcore.NewDeal(m2m.UUID(guid), "00000000-0000-0000-0000-000000000001", []byte("<xml/>"))
	if err != nil {
		t.Fatalf("NewDeal: %v", err)
	}
	return d
}

func TestFSMAllowedTransitions(t *testing.T) {
	cases := []struct {
		from m2mcore.State
		to   m2mcore.State
		ok   bool
	}{
		{m2mcore.StateDraft, m2mcore.StateValidated, true},
		{m2mcore.StateDraft, m2mcore.StateSubmittedToNSD, false},
		{m2mcore.StateValidated, m2mcore.StateSubmittedToNSD, true},
		{m2mcore.StateAwaitingDecision, m2mcore.StateConfirmed, true},
		{m2mcore.StateAwaitingDecision, m2mcore.StateRejected, true},
		{m2mcore.StateAwaitingDecision, m2mcore.StateTimedOut, true},
		{m2mcore.StateConfirmed, m2mcore.StateAwaitingSUB16, true},
		{m2mcore.StateDone, m2mcore.StateRejected, false},
		{m2mcore.StateRejected, m2mcore.StateDone, false},
	}
	for _, c := range cases {
		if got := m2mcore.CanTransition(c.from, c.to); got != c.ok {
			t.Errorf("CanTransition(%s,%s)=%v ожидалось %v", c.from, c.to, got, c.ok)
		}
	}
}

func TestFSMIsTerminal(t *testing.T) {
	for _, s := range []m2mcore.State{m2mcore.StateDone, m2mcore.StateRejected, m2mcore.StateTimedOut} {
		if !m2mcore.IsTerminal(s) {
			t.Errorf("%s должно быть терминальным", s)
		}
	}
	for _, s := range []m2mcore.State{m2mcore.StateDraft, m2mcore.StateConfirmed} {
		if m2mcore.IsTerminal(s) {
			t.Errorf("%s не должно быть терминальным", s)
		}
	}
}

func TestDealManualReject(t *testing.T) {
	d := newTestDeal(t)
	if err := d.SendToManualApproval(context.Background(), "ambiguous_decision"); err != nil {
		t.Fatalf("SendToManualApproval из Draft неожиданно дал ошибку %v", err)
	}
}

func TestDealInvalidTransition(t *testing.T) {
	d := newTestDeal(t)
	// Draft -> SubmittedToNSD не разрешён.
	err := d.Submit(context.Background())
	if !errors.Is(err, m2mcore.ErrInvalidTransition) {
		t.Errorf("ожидалась ErrInvalidTransition, получено %v", err)
	}
}

func TestDealCompleteSUB16(t *testing.T) {
	d := newTestDeal(t)
	if err := d.ApproveManually(context.Background(), "operator-1"); err == nil {
		// Из Draft нельзя сразу ApproveManually — нужен путь через
		// ManualApproval. Это тоже проверяем.
		t.Errorf("ApproveManually из Draft должен был отказать")
	}
	if err := d.SendToManualApproval(context.Background(), "test"); err != nil {
		t.Fatal(err)
	}
	if err := d.ApproveManually(context.Background(), "operator-1"); err != nil {
		t.Fatalf("ApproveManually: %v", err)
	}
	if err := d.CompleteSUB16(context.Background()); err != nil {
		t.Fatalf("CompleteSUB16: %v", err)
	}
	if d.State != m2mcore.StateDone {
		t.Errorf("конечное состояние %s, ожидалось %s", d.State, m2mcore.StateDone)
	}
}
