package skills

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	store "github.com/tidbcloud/AgentTeam/internal/store/resource/skills"
)

func skillPermissionsTestSkill(id, creator string) store.Skill {
	now := time.Date(2026, 6, 18, 1, 0, 0, 0, time.UTC)
	return store.Skill{
		ID:                id,
		WorkspaceID:       "ws_1",
		Slug:              id,
		Name:              id,
		Description:       "test skill",
		StorageScope:      "personal",
		StorageOwnerLogin: creator,
		SkillCount:        0,
		IsActive:          true,
		CreatedBy:         creator,
		UpdatedBy:         creator,
		CreatedAt:         now,
		UpdatedAt:         now,
	}
}

func skillPermissionsTestGrant(id, skillID, subjectID, role string) store.SkillGrant {
	return store.SkillGrant{
		ID:          id,
		WorkspaceID: "ws_1",
		SkillID:     skillID,
		SubjectType: "user",
		SubjectID:   subjectID,
		Role:        role,
		CreatedBy:   "usr_owner",
		UpdatedBy:   "usr_owner",
		CreatedAt:   time.Date(2026, 6, 18, 1, 0, 0, 0, time.UTC),
		UpdatedAt:   time.Date(2026, 6, 18, 1, 0, 0, 0, time.UTC),
	}
}

func skillPermissionsTestWorkspaceGrant(id, skillID, role string) store.SkillGrant {
	return store.SkillGrant{
		ID:          id,
		WorkspaceID: "ws_1",
		SkillID:     skillID,
		SubjectType: "workspace",
		SubjectID:   "ws_1",
		Role:        role,
		CreatedBy:   "usr_owner",
		UpdatedBy:   "usr_owner",
		CreatedAt:   time.Date(2026, 6, 18, 1, 0, 0, 0, time.UTC),
		UpdatedAt:   time.Date(2026, 6, 18, 1, 0, 0, 0, time.UTC),
	}
}

func TestSkillRoleCreatorIsOwnerAndNoGrantIsEmpty(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_a", "usr_owner"))
	require.NoError(t, err)
	require.Equal(t, "owner", svc.skillRole(ctx, skill, "usr_owner"))
	require.Equal(t, "", svc.skillRole(ctx, skill, "usr_other"))
}

func TestSkillRoleFromLegacyEditGrantIsView(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_b", "usr_owner"))
	require.NoError(t, err)
	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_edit_1", skill.ID, "usr_edit", "edit"))
	require.NoError(t, err)
	require.Equal(t, "view", svc.skillRole(ctx, skill, "usr_edit"))
}

func TestSkillRoleUsesWorkspaceGrantAfterUserGrant(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_workspace", "usr_owner"))
	require.NoError(t, err)
	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestWorkspaceGrant("skg_workspace", skill.ID, "view"))
	require.NoError(t, err)
	require.Equal(t, "view", svc.skillRole(ctx, skill, "usr_other"))

	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_manage", skill.ID, "usr_other", "manage"))
	require.NoError(t, err)
	require.Equal(t, "manage", svc.skillRole(ctx, skill, "usr_other"))
}

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

	for _, slug := range []string{
		"agentteam-workflow-plan-author-skills",
		"superpowers",
		"addy-agent-skills",
	} {
		skill := skillPermissionsTestSkill("skill_"+slug, "agentteam-system")
		skill.Slug = slug
		require.Equal(t, "view", svc.skillRole(ctx, skill, "usr_other"), slug)
	}

	wrongCreator := skillPermissionsTestSkill("skill_wrong_creator", "usr_owner")
	wrongCreator.Slug = "agentteam-workflow-plan-author-skills"
	require.Empty(t, svc.skillRole(ctx, wrongCreator, "usr_other"))
}

func TestListSkillPermissionsRequiresManage(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_c", "usr_owner"))
	require.NoError(t, err)
	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_owner_c", skill.ID, "usr_owner", "owner"))
	require.NoError(t, err)
	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_view_c", skill.ID, "usr_viewer", "view"))
	require.NoError(t, err)

	summary, err := svc.ListSkillPermissions(ctx, skill.WorkspaceID, "usr_owner", skill.ID)
	require.NoError(t, err)
	require.True(t, summary.CanManage)
	require.Equal(t, "owner", summary.MyRole)
	require.NotNil(t, summary.Owner)
	require.Len(t, summary.Members, 2)

	_, err = svc.ListSkillPermissions(ctx, skill.WorkspaceID, "usr_viewer", skill.ID)
	require.ErrorIs(t, err, ErrForbidden)

	_, err = svc.ListSkillPermissions(ctx, skill.WorkspaceID, "usr_other", skill.ID)
	require.ErrorIs(t, err, ErrNotFound)
}

func TestUpsertSkillPermissionOwnerCanGrantAndAgentRejected(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_d", "usr_owner"))
	require.NoError(t, err)

	grant, err := svc.UpsertSkillPermission(ctx, skill.WorkspaceID, "usr_owner", skill.ID, SkillPermissionGrantMutation{
		SubjectType: "user",
		SubjectID:   "usr_editor",
		Role:        "edit",
	})
	require.NoError(t, err)
	require.Equal(t, "view", grant.Role)
	require.Equal(t, "usr_editor", grant.SubjectID)

	_, err = svc.UpsertSkillPermission(ctx, skill.WorkspaceID, "usr_owner", skill.ID, SkillPermissionGrantMutation{
		SubjectType: "agent",
		SubjectID:   "agt_1",
		Role:        "view",
	})
	require.ErrorIs(t, err, ErrInvalidArgument)
}

func TestDeleteSkillPermissionOwnerGrantNotRemovable(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_e", "usr_owner"))
	require.NoError(t, err)
	grant, err := svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_owner_e", skill.ID, "usr_owner", "owner"))
	require.NoError(t, err)
	err = svc.DeleteSkillPermission(ctx, skill.WorkspaceID, "usr_owner", skill.ID, grant.ID)
	require.ErrorIs(t, err, ErrInvalidArgument)
}

func TestUpdateSkillRequiresManage(t *testing.T) {
	svc, _ := newSkillServiceForTest(t)
	ctx := context.Background()
	skill, err := svc.store.CreateSkill(ctx, skillPermissionsTestSkill("skill_f", "usr_owner"))
	require.NoError(t, err)
	_, err = svc.store.UpsertSkillGrant(ctx, skillPermissionsTestGrant("skg_view_f", skill.ID, "usr_viewer", "view"))
	require.NoError(t, err)
	name := "renamed"
	_, err = svc.UpdateSkill(ctx, skill.WorkspaceID, "usr_viewer", skill.ID, SkillUpdateMutation{Name: &name})
	require.ErrorIs(t, err, ErrForbidden)
}
