package roadmapsync

import (
	"testing"

	"github.com/nomadcode/nomadcode-core/internal/workitem"
)

func reconcileIdentity() Identity {
	return Identity{
		Shape:                ShapeMilestone,
		RoadmapMilestonePath: "agent-roadmap/phase/p/milestones/m.md",
		Provider:             workitem.ProviderID("plane"),
		Tenant:               "general",
		Project:              "NOMAD",
		WorkItemID:           "NOMAD-13",
	}
}

func TestReconcile_SamePlaneTicketReusesIdentity(t *testing.T) {
	id := reconcileIdentity()
	res := ReconcileCreationCycle(ReconcileInput{
		Identity: id,
		Existing: ExistingIdentity{Found: true, Identity: id},
		CompletedSteps: map[Step]bool{
			StepDevelopMatched: true,
		},
	})
	if res.Action != ActionResume {
		t.Fatalf("action: got %q, want resume (%s)", res.Action, res.Reason)
	}
	if !res.IdentityKept {
		t.Error("expected identity reuse for the same Plane ticket")
	}
	if res.NextStep != StepOriginalCommentPreserved {
		t.Errorf("next step: got %q, want original_comment_preserved", res.NextStep)
	}
}

func TestReconcile_SameMilestonePathReusesIdentity(t *testing.T) {
	id := reconcileIdentity()
	// Existing row found via the Milestone path: same path + provider work item.
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:       id,
		Existing:       ExistingIdentity{Found: true, Identity: id},
		CompletedSteps: map[Step]bool{},
	})
	if res.Action != ActionResume || !res.IdentityKept {
		t.Fatalf("expected resume with identity kept, got %q kept=%v (%s)", res.Action, res.IdentityKept, res.Reason)
	}
	if res.NextStep != StepDevelopMatched {
		t.Errorf("fresh ledger should resume at develop_matched, got %q", res.NextStep)
	}
}

func TestReconcile_ProviderRevisionMismatchConflicts(t *testing.T) {
	id := reconcileIdentity()
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:         id,
		ProviderRevision: "rev-2",
		Existing: ExistingIdentity{
			Found: true, Identity: id, ProviderRevision: "rev-1",
		},
	})
	if res.Action != ActionConflict {
		t.Fatalf("action: got %q, want conflict (%s)", res.Action, res.Reason)
	}
	if !res.IdentityKept {
		t.Error("a conflict on a matched identity should still report the identity as kept")
	}
}

func TestReconcile_RoadmapRevisionMismatchConflicts(t *testing.T) {
	id := reconcileIdentity()
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:        id,
		RoadmapRevision: "abc",
		Existing: ExistingIdentity{
			Found: true, Identity: id, RoadmapRevision: "def",
		},
	})
	if res.Action != ActionConflict {
		t.Fatalf("action: got %q, want conflict (%s)", res.Action, res.Reason)
	}
}

func TestReconcile_NomadCodeActorIsNotNewTrigger(t *testing.T) {
	id := reconcileIdentity()
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:  id,
		Actor:     "nomadcode",
		SelfActor: "nomadcode",
		Existing:  ExistingIdentity{Found: true, Identity: id},
	})
	if res.Action != ActionSkipSelfMutation {
		t.Fatalf("action: got %q, want skip_self_mutation (%s)", res.Action, res.Reason)
	}
}

func TestReconcile_DifferentTenantConflicts(t *testing.T) {
	id := reconcileIdentity()
	existing := id
	existing.Tenant = "other-workspace"
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:       id,
		Existing:       ExistingIdentity{Found: true, Identity: existing},
		CompletedSteps: map[Step]bool{},
	})
	if res.Action != ActionConflict {
		t.Fatalf("tenant mismatch should conflict, got %q (%s)", res.Action, res.Reason)
	}
	if res.IdentityKept {
		t.Error("a non-matching persisted identity must not be reported as kept")
	}
}

func TestReconcile_DifferentProjectConflicts(t *testing.T) {
	id := reconcileIdentity()
	existing := id
	existing.Project = "OTHER"
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:       id,
		Existing:       ExistingIdentity{Found: true, Identity: existing},
		CompletedSteps: map[Step]bool{},
	})
	if res.Action != ActionConflict {
		t.Fatalf("project mismatch should conflict, got %q (%s)", res.Action, res.Reason)
	}
}

func TestReconcile_AllStepsCompleteReturnsComplete(t *testing.T) {
	id := reconcileIdentity()
	res := ReconcileCreationCycle(ReconcileInput{
		Identity: id,
		Existing: ExistingIdentity{Found: true, Identity: id},
		CompletedSteps: map[Step]bool{
			StepDevelopMatched:           true,
			StepOriginalCommentPreserved: true,
			StepPlaneBodyUpdated:         true,
			StepPlaneTodoMoved:           true,
		},
	})
	if res.Action != ActionComplete {
		t.Fatalf("action: got %q, want complete (%s)", res.Action, res.Reason)
	}
}

func TestReconcile_InvalidIdentityConflicts(t *testing.T) {
	res := ReconcileCreationCycle(ReconcileInput{
		Identity: Identity{Provider: workitem.ProviderID("plane")}, // missing path + work item id
	})
	if res.Action != ActionConflict {
		t.Fatalf("action: got %q, want conflict (%s)", res.Action, res.Reason)
	}
}

func TestReconcile_FreshCycleNoExistingResumesAtFirstStep(t *testing.T) {
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:       reconcileIdentity(),
		Existing:       ExistingIdentity{Found: false},
		CompletedSteps: map[Step]bool{},
	})
	if res.Action != ActionResume || res.NextStep != StepDevelopMatched {
		t.Fatalf("fresh cycle should resume at develop_matched, got %q step=%q", res.Action, res.NextStep)
	}
	if res.IdentityKept {
		t.Error("no existing identity should report IdentityKept=false")
	}
}

func TestReconcile_FirstCycleRevisionUnknownDoesNotConflict(t *testing.T) {
	id := reconcileIdentity()
	// Existing identity has no recorded revision yet; a trigger that carries one
	// must not be blocked.
	res := ReconcileCreationCycle(ReconcileInput{
		Identity:         id,
		ProviderRevision: "rev-1",
		Existing:         ExistingIdentity{Found: true, Identity: id, ProviderRevision: ""},
		CompletedSteps:   map[Step]bool{},
	})
	if res.Action != ActionResume {
		t.Fatalf("unknown persisted revision should not conflict, got %q (%s)", res.Action, res.Reason)
	}
}
