package agent

import (
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/store/taskboard"
)

func TestTaskChecklistItemsFromDTOPreservesNilVsEmpty(t *testing.T) {
	convert := func(items []dto.TaskChecklistItem) []TaskChecklistItem {
		return taskChecklistItemsForPort(converter.FromTaskChecklistItems(items))
	}

	require.Nil(t, convert(nil))

	cleared := convert([]dto.TaskChecklistItem{})
	require.NotNil(t, cleared)
	require.Empty(t, cleared)

	converted := convert([]dto.TaskChecklistItem{{ID: "item-1", Text: "Verify", Checked: true}})
	require.Len(t, converted, 1)
	require.Equal(t, "item-1", converted[0].ID)
	require.Equal(t, "Verify", converted[0].Text)
	require.True(t, converted[0].Checked)
}

func TestAgentTaskAdaptersPreservePrincipalProfiles(t *testing.T) {
	converted := taskboardTaskForDTO(Task{
		ID: "tsk_profile",
		CreatedByProfile: &AuthorProfile{
			ActorType:   message.AuthorActorTypeHuman,
			PrincipalID: "usr_0000000creator",
			MemberID:    "00000creator",
			DisplayName: "Creator",
		},
		CreatedByType: "agent",
		CreatedByID:   "legacy_creator",
		CreatedByName: "Legacy Creator",
		AssigneeProfile: &AuthorProfile{
			ActorType:   message.AuthorActorTypeAgent,
			PrincipalID: "agt_0000000claimed",
			MemberID:    "00000claimed",
			DisplayName: "Claimed Agent",
		},
	})

	require.NotNil(t, converted.CreatedByProfile)
	require.Equal(t, "usr_0000000creator", converted.CreatedByProfile.PrincipalID)
	require.Equal(t, "user", converted.CreatedByType)
	require.Equal(t, "usr_0000000creator", converted.CreatedByID)
	require.Equal(t, "Creator", converted.CreatedByName)
	require.NotNil(t, converted.AssigneeProfile)
	require.Equal(t, "agt_0000000claimed", converted.AssigneeProfile.PrincipalID)
}

func TestAgentTaskViewReverseAdapterPreservesPrincipalProfiles(t *testing.T) {
	views := taskboardTaskViewsForDTO([]TaskView{{
		TaskScopeID: "tsk_scope",
		TaskNumber:  42,
		Title:       "Canonical list identity",
		Status:      "todo",
		CreatedByProfile: &AuthorProfile{
			ActorType:   message.AuthorActorTypeHuman,
			PrincipalID: "usr_0000000profile_creator",
			DisplayName: "Profile Creator",
		},
		CreatedByName: "Legacy Creator",
		AssigneeProfile: &AuthorProfile{
			ActorType:   message.AuthorActorTypeAgent,
			PrincipalID: "agt_0000000profile_claimed",
			DisplayName: "Profile Claimed",
		},
	}})

	require.Len(t, views, 1)
	require.NotNil(t, views[0].CreatedByProfile)
	require.Equal(t, "usr_0000000profile_creator", views[0].CreatedByProfile.PrincipalID)
	require.Equal(t, "Profile Creator", views[0].CreatedByName)
	require.NotNil(t, views[0].AssigneeProfile)
	require.Equal(t, "agt_0000000profile_claimed", views[0].AssigneeProfile.PrincipalID)
}

func TestAgentTaskAdapterPreservesSourceProvenance(t *testing.T) {
	source := message.ContributionSource{
		Kind:    message.ContributionSourceKindHumanCompose,
		RefType: message.ContributionSourceRefTypeMessage,
		RefID:   "msg_agent_task_origin",
	}

	apiTask := fromTaskboardTask(taskboard.Task{
		ID:     "tsk_agent_source",
		Source: source,
		SourceThread: &taskboard.TaskSourceThread{
			ThreadChannelID: "thr_agent_task_origin",
			ParentChannelID: "chn_agent_task_origin",
			ParentMessageID: "msg_agent_task_origin",
			Ref:             "#agent-task-origin",
		},
	})
	require.NotNil(t, apiTask.Source)
	require.Equal(t, message.ContributionSourceKindHumanCompose, apiTask.Source.Kind)
	require.Equal(t, message.ContributionSourceRefTypeMessage, apiTask.Source.RefType)
	require.Equal(t, "msg_agent_task_origin", apiTask.Source.RefID)

	converted := taskboardTaskForDTO(Task{
		ID:           apiTask.ID,
		Source:       apiTask.Source,
		SourceThread: apiTask.SourceThread,
	})
	require.Equal(t, message.ContributionSourceKindHumanCompose, converted.Source.Kind)
	require.Equal(t, message.ContributionSourceRefTypeMessage, converted.Source.RefType)
	require.Equal(t, "msg_agent_task_origin", converted.Source.RefID)
}

func TestAgentTaskDiscussionAdaptersCarryAuthorProfileAndSource(t *testing.T) {
	createdAt := time.Date(2026, 6, 2, 14, 0, 0, 0, time.UTC)
	source := taskboard.TaskDiscussionEntry{
		ID:     "msg_task_1",
		TaskID: "tsk_1",
		Body:   "agent-visible discussion",
		AuthorProfile: message.AuthorProfile{
			ActorType:   message.AuthorActorTypeService,
			PrincipalID: "appinst_tracker",
			MemberID:    "00000service",
			TargetID:    "tracker",
			DisplayName: "Tracker",
			ServiceKind: "app",
			ServiceSlug: "tracker",
		},
		Source: message.ContributionSource{
			Kind:    message.ContributionSourceKindProviderEvent,
			RefType: message.ContributionSourceRefTypeServiceEventDelivery,
			RefID:   "sed_1",
			RunID:   "sed_1",
			Label:   "PR #1",
		},
		CreatedBy: taskboard.TaskActor{Type: "agent", ID: "legacy_member", Name: "Legacy"},
		CreatedAt: createdAt,
	}

	got := fromTaskboardDiscussionEntry(source)

	require.NotNil(t, got.AuthorProfile)
	require.Equal(t, "service", got.AuthorProfile.ActorType)
	require.Equal(t, "appinst_tracker", got.AuthorProfile.PrincipalID)
	require.Equal(t, "00000service", got.AuthorProfile.MemberID)
	require.Equal(t, "Tracker", got.AuthorProfile.DisplayName)
	require.NotNil(t, got.Source)
	require.Equal(t, message.ContributionSourceKindProviderEvent, got.Source.Kind)
	require.Equal(t, message.ContributionSourceRefTypeServiceEventDelivery, got.Source.RefType)
	require.Equal(t, "sed_1", got.Source.RefID)
	require.Equal(t, "app", got.CreatedBy.Type)
	require.Equal(t, "appinst_tracker", got.CreatedBy.ID)
	require.Equal(t, "Tracker", got.CreatedBy.Name)
	require.Equal(t, createdAt, got.CreatedAt)
}

func TestAgentTaskDiscussionReverseAdapterDerivesCreatedByFromAuthorProfile(t *testing.T) {
	converted := taskboardTaskDiscussionEntryForDTO(TaskDiscussionEntry{
		ID:     "msg_task_2",
		TaskID: "tsk_2",
		Body:   "round trip discussion",
		AuthorProfile: &AuthorProfile{
			ActorType:   "agent",
			PrincipalID: "agt_0000000builder",
			MemberID:    "00000builder",
			DisplayName: "Builder",
		},
		Source: &ContributionSource{
			Kind:    message.ContributionSourceKindScheduleRun,
			RefType: message.ContributionSourceRefTypeAutomationRun,
			RefID:   "arun_1",
			RunID:   "arun_1",
		},
		CreatedBy: TaskActor{Type: "human", ID: "legacy_user", Name: "Legacy"},
	})

	require.Equal(t, message.AuthorActorTypeAgent, converted.AuthorProfile.ActorType)
	require.Equal(t, "agt_0000000builder", converted.AuthorProfile.PrincipalID)
	require.Equal(t, "00000builder", converted.AuthorProfile.MemberID)
	require.Equal(t, "Builder", converted.AuthorProfile.DisplayName)
	require.Equal(t, message.ContributionSourceKindScheduleRun, converted.Source.Kind)
	require.Equal(t, message.ContributionSourceRefTypeAutomationRun, converted.Source.RefType)
	require.Equal(t, "arun_1", converted.Source.RefID)
	require.Equal(t, "agent", converted.CreatedBy.Type)
	require.Equal(t, "agt_0000000builder", converted.CreatedBy.ID)
	require.Equal(t, "Builder", converted.CreatedBy.Name)
}

func TestAgentTaskActivityAdaptersCarryAuthorProfileAndSource(t *testing.T) {
	createdAt := time.Date(2026, 6, 2, 18, 0, 0, 0, time.UTC)
	source := taskboard.TaskActivityEvent{
		ID:   "act_task_1",
		Type: "review_requested",
		AuthorProfile: message.AuthorProfile{
			ActorType:   message.AuthorActorTypeAgent,
			PrincipalID: "agt_000000reviewer",
			MemberID:    "0000reviewer",
			TargetID:    "reviewer",
			DisplayName: "Reviewer",
		},
		Source: message.ContributionSource{
			Kind:      message.ContributionSourceKindAgentRuntime,
			RefType:   message.ContributionSourceRefTypeTaskActivity,
			RefID:     "act_task_1",
			EventType: "review_requested",
			Label:     "Reviewer",
		},
		ActorRef:         "legacy_actor",
		ActorDisplayName: "Legacy Actor",
		SourceKind:       "message",
		SourceMessageID:  "legacy_msg",
		SourceActivityID: "legacy_activity",
		CreatedAt:        createdAt,
	}

	got := fromTaskboardActivityEvent(source)

	require.NotNil(t, got.AuthorProfile)
	require.Equal(t, "agent", got.AuthorProfile.ActorType)
	require.Equal(t, "agt_000000reviewer", got.AuthorProfile.PrincipalID)
	require.NotNil(t, got.Source)
	require.Equal(t, message.ContributionSourceRefTypeTaskActivity, got.Source.RefType)
	require.Equal(t, "act_task_1", got.Source.RefID)
	require.Equal(t, "0000reviewer", got.ActorRef)
	require.Equal(t, "Reviewer", got.ActorDisplayName)
	require.Equal(t, "activity", got.SourceKind)
	require.Empty(t, got.SourceMessageID)
	require.Equal(t, "act_task_1", got.SourceActivityID)
	require.Equal(t, createdAt, got.CreatedAt)

	converted := taskboardTaskActivityEventForDTO(TaskActivityEvent{
		ID:               got.ID,
		Type:             got.Type,
		AuthorProfile:    got.AuthorProfile,
		Source:           got.Source,
		ActorRef:         "legacy_roundtrip",
		ActorDisplayName: "Legacy Roundtrip",
		SourceKind:       "message",
		SourceMessageID:  "legacy_msg_roundtrip",
		SourceActivityID: "legacy_activity_roundtrip",
	})
	require.Equal(t, message.AuthorActorTypeAgent, converted.AuthorProfile.ActorType)
	require.Equal(t, "0000reviewer", converted.ActorRef)
	require.Equal(t, "Reviewer", converted.ActorDisplayName)
	require.Equal(t, message.ContributionSourceRefTypeTaskActivity, converted.Source.RefType)
	require.Equal(t, "activity", converted.SourceKind)
	require.Empty(t, converted.SourceMessageID)
	require.Equal(t, "act_task_1", converted.SourceActivityID)
}

func TestAgentTaskFactAdaptersDeriveCompatibilityRefsFromPrincipalProfiles(t *testing.T) {
	artifact := fromTaskboardArtifact(taskboard.TaskArtifact{
		ID:   "art_1",
		Kind: "report",
		CreatedByProfile: &message.AuthorProfile{
			ActorType:   message.AuthorActorTypeService,
			PrincipalID: "svc_reporter",
			MemberID:    "0000reporter",
			DisplayName: "Reporter",
		},
		CreatedByRef: "legacy_artifact_creator",
	})
	require.NotNil(t, artifact.CreatedByProfile)
	require.Equal(t, "svc_reporter", artifact.CreatedByProfile.PrincipalID)
	require.Equal(t, "0000reporter", artifact.CreatedByRef)

	roundTrippedArtifact := taskboardTaskArtifactForDTO(TaskArtifact{
		ID:               artifact.ID,
		CreatedByProfile: artifact.CreatedByProfile,
		CreatedByRef:     "legacy_artifact_roundtrip",
	})
	require.NotNil(t, roundTrippedArtifact.CreatedByProfile)
	require.Equal(t, "svc_reporter", roundTrippedArtifact.CreatedByProfile.PrincipalID)
	require.Equal(t, "0000reporter", roundTrippedArtifact.CreatedByRef)
}
