import type {
  OrganizationRole,
  OrganizationRolesResponse,
} from '@/data/organization-members/organization-roles-query'
import type { OrganizationMember } from '@/data/organizations/organization-members-query'

export interface ProjectAccessMember {
  id: string
  displayName?: string
  email: string
  role?: string
}

interface SummarizeProjectAccessParams {
  organizationMembers: OrganizationMember[]
  roles: OrganizationRolesResponse | undefined
  projectRef?: string
  hasLimitedVisibility: boolean
  currentUserId?: string
  maxVisibleMembers?: number
}

export interface ProjectAccessSummary {
  projectMembers: ProjectAccessMember[]
  visibleMembers: ProjectAccessMember[]
  hiddenMembersCount: number
  projectMemberCount: number
  organizationMemberCount: number
  shouldShowOrgComparison: boolean
  hasOrganizationWideAccess: boolean
}

const getRoleDisplayName = (roleName: string | undefined) => {
  if (!roleName) return undefined
  return roleName.split('_')[0]
}

const roleAppliesToProject = (role: OrganizationRole | undefined, projectRef?: string) => {
  if (!role) return false
  if (role.projects.length === 0) return true
  if (!projectRef) return false
  return role.projects.some((project) => project.ref === projectRef)
}

export const summarizeProjectAccess = ({
  organizationMembers,
  roles,
  projectRef,
  hasLimitedVisibility,
  currentUserId,
  maxVisibleMembers = 12,
}: SummarizeProjectAccessParams): ProjectAccessSummary => {
  const allRoles = [...(roles?.org_scoped_roles ?? []), ...(roles?.project_scoped_roles ?? [])]
  const rolesById = new Map(allRoles.map((role) => [role.id, role]))

  const normalizedMembers = organizationMembers.filter(
    (member) => !member.invited_id && typeof member.gotrue_id === 'string' && !!member.primary_email
  )

  const membersWithProjectAccess = normalizedMembers
    .filter((member) =>
      member.role_ids.some((roleId) => roleAppliesToProject(rolesById.get(roleId), projectRef))
    )
    .sort((a, b) => {
      const isCurrentUserA = !!currentUserId && a.gotrue_id === currentUserId
      const isCurrentUserB = !!currentUserId && b.gotrue_id === currentUserId

      if (isCurrentUserA && !isCurrentUserB) return -1
      if (!isCurrentUserA && isCurrentUserB) return 1
      return (a.primary_email ?? '').localeCompare(b.primary_email ?? '')
    })

  const projectMembers = membersWithProjectAccess.map((member) => {
    const matchingRoleNames = member.role_ids
      .map((roleId) => rolesById.get(roleId))
      .filter((role) => roleAppliesToProject(role, projectRef))
      .map((role) => getRoleDisplayName(role?.name))
      .filter((name): name is string => typeof name === 'string' && name.length > 0)

    const uniqueRoleNames = [...new Set(matchingRoleNames)]
    const hasDisplayName =
      typeof member.username === 'string' &&
      typeof member.primary_email === 'string' &&
      member.username !== member.primary_email

    return {
      id: member.gotrue_id as string,
      displayName: hasDisplayName ? member.username : undefined,
      email: member.primary_email as string,
      role: uniqueRoleNames.length > 0 ? uniqueRoleNames.join(', ') : undefined,
    }
  })

  const projectMemberCount = projectMembers.length
  const organizationMemberCount = normalizedMembers.length
  const shouldShowOrgComparison = !hasLimitedVisibility && organizationMemberCount > 0
  const hasOrganizationWideAccess =
    shouldShowOrgComparison && projectMemberCount === organizationMemberCount

  return {
    projectMembers,
    visibleMembers: projectMembers.slice(0, maxVisibleMembers),
    hiddenMembersCount: Math.max(projectMemberCount - maxVisibleMembers, 0),
    projectMemberCount,
    organizationMemberCount,
    shouldShowOrgComparison,
    hasOrganizationWideAccess,
  }
}
