/**
 * Admin tenant roles query helpers — admin-dashboard.
 * Wraps tenant RBAC schema to keep raw tables out of route files.
 */
import { and, count, eq } from 'drizzle-orm'
import type { Db } from '../client'
import { roles, permissions, rolePermissions, tenantMemberships } from '../schema'

export interface TenantRoleWithPermissions {
  id: string
  tenantId: string
  name: string
  isSystemRole: boolean
  createdAt: Date
  permissionKeys: string[]
}

export async function listTenantRolesAdmin(
  db: Db,
  tenantId: string,
): Promise<TenantRoleWithPermissions[]> {
  const roleRows = await db
    .select()
    .from(roles)
    .where(eq(roles.tenantId, tenantId))
    .orderBy(roles.name)

  const permRows = await db
    .select({
      roleId: rolePermissions.roleId,
      key: permissions.key,
    })
    .from(rolePermissions)
    .innerJoin(permissions, eq(rolePermissions.permissionId, permissions.id))

  const permsByRole = new Map<string, string[]>()
  for (const row of permRows) {
    if (!permsByRole.has(row.roleId)) permsByRole.set(row.roleId, [])
    permsByRole.get(row.roleId)!.push(row.key)
  }

  return roleRows.map((r) => ({
    ...r,
    permissionKeys: permsByRole.get(r.id) ?? [],
  }))
}

export async function createTenantRole(
  db: Db,
  tenantId: string,
  name: string,
  permissionKeys: string[],
): Promise<{ id: string }> {
  const [role] = await db
    .insert(roles)
    .values({ tenantId, name, isSystemRole: false })
    .returning({ id: roles.id })

  if (permissionKeys.length > 0) {
    const permRows = await db
      .select({ id: permissions.id, key: permissions.key })
      .from(permissions)

    const matchingPerms = permRows.filter((p) => permissionKeys.includes(p.key))

    if (matchingPerms.length > 0) {
      await db.insert(rolePermissions).values(
        matchingPerms.map((p) => ({ roleId: role!.id, permissionId: p.id })),
      )
    }
  }

  return { id: role!.id }
}

export async function updateTenantRolePermissions(
  db: Db,
  tenantId: string,
  roleId: string,
  permissionKeys: string[],
): Promise<{ success: boolean; error?: string }> {
  // Verify role belongs to tenant
  const [role] = await db
    .select()
    .from(roles)
    .where(and(eq(roles.id, roleId), eq(roles.tenantId, tenantId)))
    .limit(1)

  if (!role) return { success: false, error: 'Role not found' }
  if (role.isSystemRole) return { success: false, error: 'System roles cannot be modified' }

  // Replace permissions
  await db.delete(rolePermissions).where(eq(rolePermissions.roleId, roleId))

  if (permissionKeys.length > 0) {
    const permRows = await db
      .select({ id: permissions.id, key: permissions.key })
      .from(permissions)

    const matching = permRows.filter((p) => permissionKeys.includes(p.key))
    if (matching.length > 0) {
      await db.insert(rolePermissions).values(
        matching.map((p) => ({ roleId, permissionId: p.id })),
      )
    }
  }

  return { success: true }
}

export async function deleteTenantRole(
  db: Db,
  tenantId: string,
  roleId: string,
): Promise<{ success: boolean; error?: string }> {
  const [role] = await db
    .select()
    .from(roles)
    .where(and(eq(roles.id, roleId), eq(roles.tenantId, tenantId)))
    .limit(1)

  if (!role) return { success: false, error: 'Role not found' }
  if (role.isSystemRole) return { success: false, error: 'System roles cannot be deleted' }

  const [memberCount] = await db
    .select({ cnt: count(tenantMemberships.userId) })
    .from(tenantMemberships)
    .where(eq(tenantMemberships.roleId, roleId))

  if (Number(memberCount?.cnt ?? 0) > 0) {
    return {
      success: false,
      error: 'Cannot delete role: reassign members to a different role first',
    }
  }

  await db.delete(roles).where(eq(roles.id, roleId))
  return { success: true }
}
