package kb

import (
	"context"
	"errors"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/kb"
	"gorm.io/gorm"
)

func (s *KBService) knowledgeBaseRole(ctx context.Context, base kb.KnowledgeBase, subject string) string {
	canAdministerWorkspace := s.canAdministerWorkspaceForRead(ctx, base.WorkspaceID, subject)
	return s.knowledgeBaseRoleWithWorkspaceAuthority(ctx, base, subject, canAdministerWorkspace)
}

func (s *KBService) knowledgeBaseRoleWithWorkspaceAuthority(ctx context.Context, base kb.KnowledgeBase, subject string, canAdministerWorkspace bool) string {
	subject = strings.TrimSpace(subject)
	if subject == "" {
		return ""
	}
	if strings.TrimSpace(base.CreatedBy) == subject {
		return "owner"
	}
	if canAdministerWorkspace {
		return "manage"
	}
	isDraft := strings.TrimSpace(base.PublicationState) == KBPublicationDraft
	grant, err := s.store.GetKnowledgeBaseGrant(ctx, base.WorkspaceID, base.ID, "user", subject)
	if err == nil {
		role := strings.TrimSpace(grant.Role)
		if role == "none" || (isDraft && !roleCanEdit(role)) {
			return ""
		}
		return role
	}
	if !errors.Is(err, gorm.ErrRecordNotFound) {
		return ""
	}
	if isDraft {
		return ""
	}
	return normalizedKBDefaultWorkspaceMemberRole(base.DefaultWorkspaceMemberRole)
}

func (s *KBService) knowledgeBaseVisibleToSubjectWithWorkspaceAuthority(ctx context.Context, base kb.KnowledgeBase, subject string, canAdministerWorkspace bool) bool {
	return s.knowledgeBaseRoleWithWorkspaceAuthority(ctx, base, subject, canAdministerWorkspace) != ""
}

func (s *KBService) canManageKnowledgeBase(ctx context.Context, base kb.KnowledgeBase, subject string) bool {
	subject = strings.TrimSpace(subject)
	if subject == "" {
		return false
	}
	return roleCanManage(s.knowledgeBaseRole(ctx, base, subject))
}

func (s *KBService) canViewKnowledgeBase(ctx context.Context, base kb.KnowledgeBase, subject string) bool {
	subject = strings.TrimSpace(subject)
	if subject == "" {
		return false
	}
	return s.knowledgeBaseRole(ctx, base, subject) != ""
}

func roleCanManage(role string) bool {
	switch strings.TrimSpace(role) {
	case "owner", "manage":
		return true
	default:
		return false
	}
}

func roleCanEdit(role string) bool {
	switch strings.TrimSpace(role) {
	case "owner", "manage", "edit":
		return true
	default:
		return false
	}
}

func normalizeKBGrantSubjectType(subjectType string) string {
	switch strings.TrimSpace(subjectType) {
	case "user", "agent":
		return strings.TrimSpace(subjectType)
	default:
		return ""
	}
}

func normalizeKBGrantRole(role, subjectType string) string {
	role = strings.TrimSpace(role)
	if subjectType == "agent" {
		return "view"
	}
	switch role {
	case "owner", "manage", "edit", "view", "none":
		return role
	default:
		return "view"
	}
}

func normalizeKBDefaultWorkspaceMemberRole(role *string) (string, error) {
	if role == nil {
		return "view", nil
	}
	switch strings.TrimSpace(*role) {
	case "manage", "edit", "view":
		return strings.TrimSpace(*role), nil
	default:
		return "", invalidArgument("default workspace member role must be view, edit, or manage")
	}
}

func normalizeKBDefaultRepositoryAccessProfile(profile *string) (string, error) {
	if profile == nil {
		return kb.KnowledgeBaseRepositoryAccessProfileNone, nil
	}
	return normalizeKBRepositoryAccessProfile(*profile)
}

func normalizedKBDefaultRepositoryAccessProfile(profile string) string {
	trimmed := strings.TrimSpace(profile)
	if trimmed == "" {
		return kb.KnowledgeBaseRepositoryAccessProfileNone
	}
	return trimmed
}

func normalizedKBDefaultWorkspaceMemberRole(role string) string {
	switch strings.TrimSpace(role) {
	case "manage", "edit", "view":
		return strings.TrimSpace(role)
	default:
		return "view"
	}
}

func normalizeKBRepositoryAccessProfile(profile string) (string, error) {
	switch strings.TrimSpace(profile) {
	case "", kb.KnowledgeBaseRepositoryAccessProfileNone:
		return kb.KnowledgeBaseRepositoryAccessProfileNone, nil
	case kb.KnowledgeBaseRepositoryAccessProfileRead:
		return kb.KnowledgeBaseRepositoryAccessProfileRead, nil
	case kb.KnowledgeBaseRepositoryAccessProfileWrite:
		return kb.KnowledgeBaseRepositoryAccessProfileWrite, nil
	case kb.KnowledgeBaseRepositoryAccessProfileManage:
		return kb.KnowledgeBaseRepositoryAccessProfileManage, nil
	default:
		return "", invalidArgument("repository access profile must be none, read, write, or manage")
	}
}
