import type { Board, BoardRole, OrganizationRole } from "@prisma/client";
import { prisma } from "./prisma";
import { HttpError } from "../middleware/errorHandler";

/** Global, cross-workspace admins — set via the "System admin" toggle — have full
 * access everywhere, independent of any per-workspace or per-board membership. */
export async function isSystemAdmin(userId: string): Promise<boolean> {
  const user = await prisma.user.findUnique({ where: { id: userId }, select: { isSystemAdmin: true } });
  return user?.isSystemAdmin ?? false;
}

const ORG_ROLE_RANK: Record<OrganizationRole, number> = { OWNER: 2, ADMIN: 1, MEMBER: 0 };

export async function isOrganizationAdmin(userId: string, organizationId: string): Promise<boolean> {
  const membership = await prisma.organizationMember.findUnique({
    where: { organizationId_userId: { organizationId, userId } },
  });
  return !!membership && ORG_ROLE_RANK[membership.role] >= ORG_ROLE_RANK.ADMIN;
}

export async function requireOrganizationMembership(userId: string, organizationId: string) {
  const membership = await prisma.organizationMember.findUnique({
    where: { organizationId_userId: { organizationId, userId } },
  });
  if (membership) return membership;

  if (await isSystemAdmin(userId)) {
    return { id: "system-admin", organizationId, userId, role: "OWNER" as const, joinedAt: new Date() };
  }

  throw new HttpError(403, "You are not a member of this organization");
}

export async function requireOrganizationAdmin(userId: string, organizationId: string) {
  const membership = await requireOrganizationMembership(userId, organizationId);
  if (ORG_ROLE_RANK[membership.role] < ORG_ROLE_RANK.ADMIN) {
    throw new HttpError(403, "Only organization admins can do this");
  }
  return membership;
}

/** The org's top authority — the only ones who can delete the organization or grant
 * (or revoke) the Owner role itself. Platform system admins can also always do this,
 * consistent with how they bypass every other access check in the app — checked
 * directly here (not just via requireOrganizationMembership's bypass) because a
 * system admin who already holds a lower-rank membership row would otherwise have
 * that row take precedence over their platform-level authority. */
export async function requireOrganizationOwner(userId: string, organizationId: string) {
  const membership = await requireOrganizationMembership(userId, organizationId);
  if (membership.role !== "OWNER" && !(await isSystemAdmin(userId))) {
    throw new HttpError(403, "Only the organization owner can do this");
  }
  return membership;
}

/** Grants baseline organization membership (role MEMBER) as a side effect of joining
 * one of its workspaces/boards via invite — so the org shows up in their switcher and
 * they're recognized as part of the company — without ever downgrading an existing,
 * higher-privilege membership (e.g. if they're already that org's admin). */
export async function ensureOrganizationMembership(userId: string, organizationId: string) {
  await prisma.organizationMember.upsert({
    where: { organizationId_userId: { organizationId, userId } },
    update: {},
    create: { organizationId, userId, role: "MEMBER" },
  });
}

export async function requireWorkspaceMembership(userId: string, workspaceId: string) {
  const membership = await prisma.workspaceMember.findUnique({
    where: { workspaceId_userId: { workspaceId, userId } },
  });
  if (membership) return membership;

  if (await isSystemAdmin(userId)) {
    return { id: "system-admin", workspaceId, userId, role: "ADMIN" as const, joinedAt: new Date() };
  }

  // Organization admins ("super admins" of the company) have admin access to every
  // workspace (department) in their organization, even ones they haven't been
  // explicitly added to individually.
  const workspace = await prisma.workspace.findUnique({
    where: { id: workspaceId },
    select: { organizationId: true },
  });
  if (workspace && (await isOrganizationAdmin(userId, workspace.organizationId))) {
    return { id: "org-admin", workspaceId, userId, role: "ADMIN" as const, joinedAt: new Date() };
  }

  throw new HttpError(403, "You are not a member of this workspace");
}

export async function requireWorkspaceAdmin(userId: string, workspaceId: string) {
  const membership = await requireWorkspaceMembership(userId, workspaceId);
  if (membership.role !== "ADMIN") {
    throw new HttpError(403, "Only workspace admins can do this");
  }
  return membership;
}

const ROLE_RANK: Record<BoardRole, number> = { VIEWER: 0, MEMBER: 1, ADMIN: 2 };

export async function resolveBoardAccess(userId: string, board: Board): Promise<BoardRole | null> {
  if (await isSystemAdmin(userId)) return "ADMIN";

  const workspace = await prisma.workspace.findUnique({
    where: { id: board.workspaceId },
    select: { organizationId: true },
  });
  if (workspace && (await isOrganizationAdmin(userId, workspace.organizationId))) return "ADMIN";

  const workspaceMembership = await prisma.workspaceMember.findUnique({
    where: { workspaceId_userId: { workspaceId: board.workspaceId, userId } },
  });

  // Workspace admins ("super admins" of that department) can see and manage every
  // board in the workspace, regardless of visibility or individual board membership.
  if (workspaceMembership?.role === "ADMIN") return "ADMIN";

  const boardMembership = await prisma.boardMember.findUnique({
    where: { boardId_userId: { boardId: board.id, userId } },
  });
  if (boardMembership) return boardMembership.role;

  if (board.visibility === "WORKSPACE" && workspaceMembership) {
    return "MEMBER";
  }

  if (board.visibility === "PUBLIC") {
    return "VIEWER";
  }

  return null;
}

export async function requireBoardAccess(
  userId: string,
  boardId: string,
  minRole: BoardRole = "VIEWER"
): Promise<Board> {
  const board = await prisma.board.findUnique({ where: { id: boardId } });
  if (!board) {
    throw new HttpError(404, "Board not found");
  }

  const role = await resolveBoardAccess(userId, board);
  if (!role || ROLE_RANK[role] < ROLE_RANK[minRole]) {
    throw new HttpError(403, "You don't have access to this board");
  }

  return board;
}

/** All board ids a user can see: explicit board membership, workspace admin (everywhere),
 * or a WORKSPACE-visibility board within a workspace they belong to. System admins see
 * every board on the platform. */
export async function getAccessibleBoardIds(userId: string): Promise<string[]> {
  if (await isSystemAdmin(userId)) {
    const allBoards = await prisma.board.findMany({ select: { id: true } });
    return allBoards.map((b) => b.id);
  }

  const [memberBoardIds, adminWorkspaceBoardIds, adminOrgBoardIds, workspaceVisibilityBoardIds] = await Promise.all([
    prisma.boardMember.findMany({ where: { userId }, select: { boardId: true } }),
    prisma.board.findMany({
      where: { workspace: { members: { some: { userId, role: "ADMIN" } } } },
      select: { id: true },
    }),
    prisma.board.findMany({
      where: { workspace: { organization: { members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } } } },
      select: { id: true },
    }),
    prisma.board.findMany({
      where: {
        visibility: "WORKSPACE",
        workspace: { members: { some: { userId } } },
      },
      select: { id: true },
    }),
  ]);

  return [
    ...new Set([
      ...memberBoardIds.map((b) => b.boardId),
      ...adminWorkspaceBoardIds.map((b) => b.id),
      ...adminOrgBoardIds.map((b) => b.id),
      ...workspaceVisibilityBoardIds.map((b) => b.id),
    ]),
  ];
}
