package skills

import (
	"context"
	"testing"

	"github.com/tidbcloud/AgentTeam/internal/service/resource/activity"
	"github.com/tidbcloud/AgentTeam/internal/store/resource/repos"

	"github.com/stretchr/testify/require"
)

func TestSkillServiceWritesControlPlaneActivityEvents(t *testing.T) {
	ctx := context.Background()
	svc, _ := newSkillServiceForTest(t)

	skill, err := svc.CreateSkill(ctx, "ws_1", "usr_1", SkillCreateMutation{Name: "Reviewer"})
	require.NoError(t, err)
	viewerGrant, err := svc.UpsertSkillPermission(ctx, "ws_1", "usr_1", skill.ID, SkillPermissionGrantMutation{SubjectType: "user", SubjectID: "usr_viewer", Role: "view"})
	require.NoError(t, err)
	_, err = svc.UpsertSkillPermission(ctx, "ws_1", "usr_1", skill.ID, SkillPermissionGrantMutation{GrantID: viewerGrant.ID, Role: "manage"})
	require.NoError(t, err)
	_, err = svc.BindAgentSkill(ctx, "ws_1", "usr_1", "agt_1", skill.ID, AgentSkillBindingMutation{Branch: "main"})
	require.NoError(t, err)
	_, err = svc.BindAgentSkill(ctx, "ws_1", "usr_1", "agt_2", skill.ID, AgentSkillBindingMutation{Branch: "main"})
	require.NoError(t, err)
	_, err = svc.UnbindAgentSkill(ctx, "ws_1", "usr_1", "agt_1", skill.ID)
	require.NoError(t, err)
	_, err = svc.ImportSkillContent(ctx, "ws_1", "usr_1", skill.ID, SkillContentImportMutation{SourceFilePath: "/tmp/skills.zip", SourceName: "skills.zip"})
	require.NoError(t, err)
	require.NoError(t, svc.DeleteSkillPermission(ctx, "ws_1", "usr_1", skill.ID, viewerGrant.ID))

	page, err := svc.ListSkillActivity(ctx, "ws_1", "usr_1", activity.ResourceActivityListOptions{Limit: 20})
	require.NoError(t, err)
	counts := map[string]int{}
	byType := map[string]activity.ResourceActivityItem{}
	for _, item := range page.Items {
		counts[item.EventType]++
		if _, exists := byType[item.EventType]; !exists {
			byType[item.EventType] = item
		}
	}
	require.Equal(t, 1, counts[skillActivityCreated])
	require.Equal(t, 1, counts[skillActivityBranchPinned])
	require.Equal(t, 1, counts[skillActivityGrantAdded])
	require.Equal(t, 1, counts[skillActivityGrantRoleChanged])
	require.Equal(t, 2, counts[skillActivityBound])
	require.Equal(t, 1, counts[skillActivityUnbound])
	require.Equal(t, 1, counts[skillActivityImported])
	require.Equal(t, 1, counts[skillActivityGrantRemoved])

	created := byType[skillActivityCreated]
	require.Equal(t, "created", created.SummaryKey)
	require.Equal(t, "resource", created.Target.Kind)
	require.Equal(t, "usr_1", created.Actor.ID)
	require.Equal(t, "", created.Actor.Name)
	require.Equal(t, "usr_1/reviewer.sk", created.RepoFullName)

	branchPinned := byType[skillActivityBranchPinned]
	require.Equal(t, "settings", branchPinned.Target.Kind)
	require.Equal(t, "main", branchPinned.Target.ID)
	require.Equal(t, "main", branchPinned.Details["branch"])

	grantChanged := byType[skillActivityGrantRoleChanged]
	require.Equal(t, "grant", grantChanged.Target.Kind)
	require.Equal(t, viewerGrant.ID, grantChanged.Target.ID)
	require.Equal(t, "usr_viewer", grantChanged.Details["subjectName"])
	require.Equal(t, "view", grantChanged.Details["previousRole"])
	require.Equal(t, "manage", grantChanged.Details["role"])

	bound := byType[skillActivityBound]
	require.Equal(t, "binding", bound.Target.Kind)
	require.Contains(t, []string{"agt_1", "agt_2"}, bound.Target.ID)
	require.Contains(t, []string{"agt_1", "agt_2"}, bound.Details["agentName"])

	imported := byType[skillActivityImported]
	require.Equal(t, "resource", imported.Target.Kind)
	require.Equal(t, "skills.zip", imported.Details["sourceName"])
	require.Equal(t, float64(2), imported.Details["skillCount"])
	require.Equal(t, "def456", imported.Details["commitSha"])

	removed := byType[skillActivityGrantRemoved]
	require.Equal(t, "grant", removed.Target.Kind)
	require.Equal(t, "usr_viewer", removed.Details["subjectId"])
}

func TestSkillServiceWritesResourceRepositoryLifecycleActivity(t *testing.T) {
	ctx := context.Background()
	svc, _ := newSkillServiceForTest(t)

	skill, err := svc.CreateSkill(ctx, "ws_1", "usr_1", SkillCreateMutation{Name: "Reviewer"})
	require.NoError(t, err)
	repo, err := svc.repositoryStore.Get(ctx, "ws_1", "skill_repository", skill.ID, repos.RepoRolePrimary)
	require.NoError(t, err)

	created, err := svc.activityStore.GetBySourceEventID(ctx, "ws_1", activity.ActivitySourceControl, activity.ResourceActivityControlSourceEventID(repo.ResourceType, repo.ResourceID, repo.RepoRole, "created"))
	require.NoError(t, err)
	require.Equal(t, activity.ResourceRepositoryActivityCreated, created.EventType)
	require.Equal(t, "repository", created.TargetKind)
	require.Equal(t, "usr_1/reviewer.sk", created.TargetID)
	require.Equal(t, "usr_1/reviewer.sk", created.RepoFullName)
	require.Equal(t, "usr_1", created.ActorID)

	require.NoError(t, svc.DeleteSkill(ctx, "ws_1", "usr_1", skill.ID))

	deleted, err := svc.activityStore.GetBySourceEventID(ctx, "ws_1", activity.ActivitySourceControl, activity.ResourceActivityControlSourceEventID(repo.ResourceType, repo.ResourceID, repo.RepoRole, "deleted"))
	require.NoError(t, err)
	require.Equal(t, activity.ResourceRepositoryActivityDeleted, deleted.EventType)
	require.Equal(t, "repository", deleted.TargetKind)
	require.Equal(t, "usr_1/reviewer.sk", deleted.TargetID)
	require.Equal(t, "usr_1", deleted.ActorID)
}
