"use client";

export const dynamic = "force-dynamic";

import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";

import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Building2, Copy, UserPlus, Users } from "lucide-react";

import { ApiError, customFetch } from "@/api/mutator";
import {
  type listBoardsApiV1BoardsGetResponse,
  useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import {
  type getMyOrgApiV1OrganizationsMeGetResponse,
  type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
  type getOrgMemberApiV1OrganizationsMeMembersMemberIdGetResponse,
  getListMyOrganizationsApiV1OrganizationsMeListGetQueryKey,
  type listOrgInvitesApiV1OrganizationsMeInvitesGetResponse,
  type listOrgMembersApiV1OrganizationsMeMembersGetResponse,
  getGetOrgMemberApiV1OrganizationsMeMembersMemberIdGetQueryKey,
  getListOrgInvitesApiV1OrganizationsMeInvitesGetQueryKey,
  getListOrgMembersApiV1OrganizationsMeMembersGetQueryKey,
  useCreateOrgInviteApiV1OrganizationsMeInvitesPost,
  useGetMyOrgApiV1OrganizationsMeGet,
  useGetMyMembershipApiV1OrganizationsMeMemberGet,
  useGetOrgMemberApiV1OrganizationsMeMembersMemberIdGet,
  useListOrgInvitesApiV1OrganizationsMeInvitesGet,
  useListOrgMembersApiV1OrganizationsMeMembersGet,
  useRevokeOrgInviteApiV1OrganizationsMeInvitesInviteIdDelete,
  useUpdateMemberAccessApiV1OrganizationsMeMembersMemberIdAccessPut,
  useUpdateOrgMemberApiV1OrganizationsMeMembersMemberIdPatch,
} from "@/api/generated/organizations/organizations";
import type {
  BoardRead,
  OrganizationBoardAccessSpec,
  OrganizationInviteRead,
  OrganizationMemberRead,
} from "@/api/generated/model";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { formatTimestamp } from "@/lib/formatters";
import { cn } from "@/lib/utils";

type AccessScope = "all" | "custom";

type BoardAccessState = Record<string, { read: boolean; write: boolean }>;

const buildAccessList = (
  access: BoardAccessState,
): OrganizationBoardAccessSpec[] =>
  Object.entries(access)
    .filter(([, entry]) => entry.read || entry.write)
    .map(([boardId, entry]) => ({
      board_id: boardId,
      can_read: entry.read || entry.write,
      can_write: entry.write,
    }));

const summarizeAccess = (allRead: boolean, allWrite: boolean) => {
  if (allRead || allWrite) {
    if (allRead && allWrite) return "All boards: read + write";
    if (allWrite) return "All boards: write";
    return "All boards: read";
  }
  return "Selected boards";
};

const roleBadgeVariant = (role: string) => {
  if (role === "admin" || role === "owner") return "accent" as const;
  return "outline" as const;
};

const defaultBoardAccess: BoardAccessState = {};

const initialsFrom = (value?: string | null) => {
  if (!value) return "?";
  const parts = value.trim().split(/\s+/).filter(Boolean);
  if (parts.length === 0) return "?";
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
  return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
};

function BoardAccessEditor({
  boards,
  scope,
  onScopeChange,
  allRead,
  allWrite,
  onAllReadChange,
  onAllWriteChange,
  access,
  onAccessChange,
  disabled,
  emptyMessage,
}: {
  boards: BoardRead[];
  scope: AccessScope;
  onScopeChange: (scope: AccessScope) => void;
  allRead: boolean;
  allWrite: boolean;
  onAllReadChange: (next: boolean) => void;
  onAllWriteChange: (next: boolean) => void;
  access: BoardAccessState;
  onAccessChange: (next: BoardAccessState) => void;
  disabled?: boolean;
  emptyMessage?: string;
}) {
  const handleAllReadToggle = () => {
    if (disabled) return;
    const next = !allRead;
    onAllReadChange(next);
    if (!next && allWrite) {
      onAllWriteChange(false);
    }
  };

  const handleAllWriteToggle = () => {
    if (disabled) return;
    const next = !allWrite;
    onAllWriteChange(next);
    if (next && !allRead) {
      onAllReadChange(true);
    }
  };

  const updateBoardAccess = (
    boardId: string,
    next: { read: boolean; write: boolean },
  ) => {
    onAccessChange({
      ...access,
      [boardId]: {
        read: next.read || next.write,
        write: next.write,
      },
    });
  };

  const handleBoardReadToggle = (boardId: string) => {
    if (disabled) return;
    const current = access[boardId] ?? { read: false, write: false };
    const nextRead = !current.read;
    const nextWrite = nextRead ? current.write : false;
    updateBoardAccess(boardId, { read: nextRead, write: nextWrite });
  };

  const handleBoardWriteToggle = (boardId: string) => {
    if (disabled) return;
    const current = access[boardId] ?? { read: false, write: false };
    const nextWrite = !current.write;
    const nextRead = nextWrite ? true : current.read;
    updateBoardAccess(boardId, { read: nextRead, write: nextWrite });
  };

  return (
    <div className="space-y-3">
      <div>
        <p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
          Board access
        </p>
        <div className="mt-3 inline-flex rounded-xl border border-slate-200 bg-slate-100 p-1">
          <button
            type="button"
            className={cn(
              "rounded-md px-3 py-1.5 text-xs font-semibold transition",
              scope === "all"
                ? "bg-white text-slate-900 shadow-sm"
                : "text-slate-500 hover:text-slate-700",
            )}
            onClick={() => onScopeChange("all")}
            disabled={disabled}
          >
            All boards
          </button>
          <button
            type="button"
            className={cn(
              "rounded-md px-3 py-1.5 text-xs font-semibold transition",
              scope === "custom"
                ? "bg-white text-slate-900 shadow-sm"
                : "text-slate-500 hover:text-slate-700",
            )}
            onClick={() => onScopeChange("custom")}
            disabled={disabled}
          >
            Selected boards
          </button>
        </div>
      </div>

      {scope === "all" ? (
        <div className="flex flex-wrap items-center gap-6 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm">
          <label className="flex items-center gap-2 text-slate-600">
            <input
              type="checkbox"
              className="h-4 w-4"
              checked={allRead}
              onChange={handleAllReadToggle}
              disabled={disabled}
            />
            Read
          </label>
          <label className="flex items-center gap-2 text-slate-600">
            <input
              type="checkbox"
              className="h-4 w-4"
              checked={allWrite}
              onChange={handleAllWriteToggle}
              disabled={disabled}
            />
            Write
          </label>
          <span className="text-xs text-slate-500">
            Write access implies read permissions.
          </span>
        </div>
      ) : (
        <div>
          {boards.length === 0 ? (
            <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
              {emptyMessage ?? "No boards available yet."}
            </div>
          ) : (
            <div className="overflow-hidden rounded-xl border border-slate-200">
              <table className="min-w-full text-sm">
                <thead className="bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500">
                  <tr>
                    <th className="px-4 py-2 text-left font-medium">Board</th>
                    <th className="px-4 py-2 text-center font-medium">Read</th>
                    <th className="px-4 py-2 text-center font-medium">Write</th>
                  </tr>
                </thead>
                <tbody>
                  {boards.map((board) => {
                    const entry = access[board.id] ?? {
                      read: false,
                      write: false,
                    };
                    return (
                      <tr
                        key={board.id}
                        className="border-t border-slate-200 hover:bg-slate-50"
                      >
                        <td className="px-4 py-3">
                          <div className="text-sm font-semibold text-slate-900">
                            {board.name}
                          </div>
                          <div className="text-xs text-slate-500">
                            {board.slug}
                          </div>
                        </td>
                        <td className="px-4 py-3 text-center">
                          <input
                            type="checkbox"
                            className="h-4 w-4"
                            checked={entry.read}
                            onChange={() => handleBoardReadToggle(board.id)}
                            disabled={disabled}
                          />
                        </td>
                        <td className="px-4 py-3 text-center">
                          <input
                            type="checkbox"
                            className="h-4 w-4"
                            checked={entry.write}
                            onChange={() => handleBoardWriteToggle(board.id)}
                            disabled={disabled}
                          />
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export default function OrganizationPage() {
  const { isSignedIn } = useAuth();
  const router = useRouter();
  const queryClient = useQueryClient();

  const [inviteDialogOpen, setInviteDialogOpen] = useState(false);
  const [inviteEmail, setInviteEmail] = useState("");
  const [inviteRole, setInviteRole] = useState("member");
  const [inviteScope, setInviteScope] = useState<AccessScope>("all");
  const [inviteAllRead, setInviteAllRead] = useState(true);
  const [inviteAllWrite, setInviteAllWrite] = useState(false);
  const [inviteAccess, setInviteAccess] =
    useState<BoardAccessState>(defaultBoardAccess);
  const [inviteError, setInviteError] = useState<string | null>(null);
  const [copiedInviteId, setCopiedInviteId] = useState<string | null>(null);

  const [accessDialogOpen, setAccessDialogOpen] = useState(false);
  const [activeMemberId, setActiveMemberId] = useState<string | null>(null);
  const [accessScope, setAccessScope] = useState<AccessScope | null>(null);
  const [accessAllRead, setAccessAllRead] = useState<boolean | null>(null);
  const [accessAllWrite, setAccessAllWrite] = useState<boolean | null>(null);
  const [accessRole, setAccessRole] = useState<string | null>(null);
  const [accessMap, setAccessMap] = useState<BoardAccessState | null>(null);
  const [accessError, setAccessError] = useState<string | null>(null);
  const [deleteOrgOpen, setDeleteOrgOpen] = useState(false);
  const [removeMemberOpen, setRemoveMemberOpen] = useState(false);

  const orgQuery = useGetMyOrgApiV1OrganizationsMeGet<
    getMyOrgApiV1OrganizationsMeGetResponse,
    ApiError
  >({
    query: {
      enabled: Boolean(isSignedIn),
      refetchOnMount: "always",
    },
  });

  const membersQuery = useListOrgMembersApiV1OrganizationsMeMembersGet<
    listOrgMembersApiV1OrganizationsMeMembersGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchOnMount: "always",
      },
    },
  );

  const boardsQuery = useListBoardsApiV1BoardsGet<
    listBoardsApiV1BoardsGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchOnMount: "always",
      },
    },
  );

  const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
    getMyMembershipApiV1OrganizationsMeMemberGetResponse,
    ApiError
  >({
    query: {
      enabled: Boolean(isSignedIn),
      refetchOnMount: "always",
    },
  });

  const membershipRole =
    membershipQuery.data?.status === 200 ? membershipQuery.data.data.role : null;
  const isOwner = membershipRole === "owner";
  const isAdmin = membershipRole === "admin" || membershipRole === "owner";

  const invitesQuery = useListOrgInvitesApiV1OrganizationsMeInvitesGet<
    listOrgInvitesApiV1OrganizationsMeInvitesGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn && isAdmin),
        refetchOnMount: "always",
        retry: false,
      },
    },
  );

  const members = useMemo(() => {
    if (membersQuery.data?.status !== 200) return [];
    return membersQuery.data.data.items ?? [];
  }, [membersQuery.data]);

  const invites = useMemo<OrganizationInviteRead[]>(() => {
    if (invitesQuery.data?.status !== 200) return [];
    return invitesQuery.data.data.items ?? [];
  }, [invitesQuery.data]);

  const boards = useMemo<BoardRead[]>(() => {
    if (boardsQuery.data?.status !== 200) return [];
    return boardsQuery.data.data.items ?? [];
  }, [boardsQuery.data]);

  const memberDetailsQuery =
    useGetOrgMemberApiV1OrganizationsMeMembersMemberIdGet<
      getOrgMemberApiV1OrganizationsMeMembersMemberIdGetResponse,
      ApiError
    >(activeMemberId ?? "", {
      query: {
        enabled: Boolean(activeMemberId && accessDialogOpen),
      },
    });

  const memberDetails =
    memberDetailsQuery.data?.status === 200
      ? memberDetailsQuery.data.data
      : null;

  const defaultAccess = useMemo(() => {
    if (!memberDetails) {
      return {
        role: "member",
        scope: "all" as AccessScope,
        allRead: false,
        allWrite: false,
        access: {},
      };
    }
    const isAll =
      memberDetails.all_boards_read || memberDetails.all_boards_write;
    const nextAccess: BoardAccessState = {};
    for (const entry of memberDetails.board_access ?? []) {
      nextAccess[entry.board_id] = {
        read: entry.can_read || entry.can_write,
        write: entry.can_write,
      };
    }
    return {
      role: memberDetails.role,
      scope: isAll ? "all" : ("custom" as AccessScope),
      allRead: memberDetails.all_boards_read,
      allWrite: memberDetails.all_boards_write,
      access: nextAccess,
    };
  }, [memberDetails]);

  const resolvedAccessRole = accessRole ?? defaultAccess.role;
  const resolvedAccessScope = accessScope ?? defaultAccess.scope;
  const resolvedAccessAllRead = accessAllRead ?? defaultAccess.allRead;
  const resolvedAccessAllWrite = accessAllWrite ?? defaultAccess.allWrite;
  const resolvedAccessMap = accessMap ?? defaultAccess.access;

  const createInviteMutation =
    useCreateOrgInviteApiV1OrganizationsMeInvitesPost<ApiError>({
      mutation: {
        onSuccess: (result) => {
          if (result.status === 200) {
            setInviteEmail("");
            setInviteRole("member");
            setInviteScope("all");
            setInviteAllRead(true);
            setInviteAllWrite(false);
            setInviteAccess(defaultBoardAccess);
            setInviteError(null);
            queryClient.invalidateQueries({
              queryKey: getListOrgInvitesApiV1OrganizationsMeInvitesGetQueryKey(
                {
                  limit: 200,
                },
              ),
            });
            setInviteDialogOpen(false);
          }
        },
        onError: (err) => {
          setInviteError(err.message || "Unable to create invite.");
        },
      },
    });

  const revokeInviteMutation =
    useRevokeOrgInviteApiV1OrganizationsMeInvitesInviteIdDelete<ApiError>({
      mutation: {
        onSuccess: () => {
          queryClient.invalidateQueries({
            queryKey: getListOrgInvitesApiV1OrganizationsMeInvitesGetQueryKey({
              limit: 200,
            }),
          });
        },
      },
    });

  const updateMemberAccessMutation =
    useUpdateMemberAccessApiV1OrganizationsMeMembersMemberIdAccessPut<ApiError>(
      {
        mutation: {
          onSuccess: () => {
            queryClient.invalidateQueries({
              queryKey: getListOrgMembersApiV1OrganizationsMeMembersGetQueryKey(
                {
                  limit: 200,
                },
              ),
            });
            if (activeMemberId) {
              queryClient.invalidateQueries({
                queryKey:
                  getGetOrgMemberApiV1OrganizationsMeMembersMemberIdGetQueryKey(
                    activeMemberId,
                  ),
              });
            }
          },
        },
      },
    );

  const updateMemberRoleMutation =
    useUpdateOrgMemberApiV1OrganizationsMeMembersMemberIdPatch<ApiError>({
      mutation: {
        onSuccess: () => {
          queryClient.invalidateQueries({
            queryKey: getListOrgMembersApiV1OrganizationsMeMembersGetQueryKey({
              limit: 200,
            }),
          });
        },
      },
    });

  const deleteOrganizationMutation = useMutation<
    { data: unknown; status: number; headers: Headers },
    ApiError
  >({
    mutationFn: async () =>
      customFetch<{ data: unknown; status: number; headers: Headers }>(
        "/api/v1/organizations/me",
        { method: "DELETE" },
      ),
    onSuccess: async () => {
      setDeleteOrgOpen(false);
      await queryClient.invalidateQueries({
        queryKey: getListMyOrganizationsApiV1OrganizationsMeListGetQueryKey(),
      });
      router.push("/dashboard");
      router.refresh();
    },
  });

  const removeMemberMutation = useMutation<
    { data: unknown; status: number; headers: Headers },
    ApiError,
    { memberId: string }
  >({
    mutationFn: async ({ memberId }) =>
      customFetch<{ data: unknown; status: number; headers: Headers }>(
        `/api/v1/organizations/me/members/${memberId}`,
        { method: "DELETE" },
      ),
    onSuccess: async () => {
      setRemoveMemberOpen(false);
      setAccessDialogOpen(false);
      setActiveMemberId(null);
      await queryClient.invalidateQueries({
        queryKey: getListOrgMembersApiV1OrganizationsMeMembersGetQueryKey({
          limit: 200,
        }),
      });
    },
  });

  const resetAccessState = () => {
    setAccessRole(null);
    setAccessScope(null);
    setAccessAllRead(null);
    setAccessAllWrite(null);
    setAccessMap(null);
    setAccessError(null);
  };

  const handleAccessDialogChange = (open: boolean) => {
    setAccessDialogOpen(open);
    if (!open) {
      setActiveMemberId(null);
      setAccessError(null);
      return;
    }
    resetAccessState();
  };

  const handleInviteDialogChange = (open: boolean) => {
    setInviteDialogOpen(open);
    if (!open) {
      setInviteError(null);
    }
  };

  const orgName =
    orgQuery.data?.status === 200 ? orgQuery.data.data.name : "Organization";

  const handleInviteSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (!isSignedIn || !isAdmin) return;

    const trimmedEmail = inviteEmail.trim().toLowerCase();
    if (!trimmedEmail || !trimmedEmail.includes("@")) {
      setInviteError("Enter a valid email address.");
      return;
    }

    const hasAllAccess =
      inviteScope === "all" && (inviteAllRead || inviteAllWrite);
    const inviteAccessList = buildAccessList(inviteAccess);
    const hasCustomAccess =
      inviteScope === "custom" && inviteAccessList.length > 0;

    if (!hasAllAccess && !hasCustomAccess) {
      setInviteError("Select read or write access for at least one board.");
      return;
    }

    setInviteError(null);
    createInviteMutation.mutate({
      data: {
        invited_email: trimmedEmail,
        role: inviteRole,
        all_boards_read: inviteScope === "all" ? inviteAllRead : false,
        all_boards_write: inviteScope === "all" ? inviteAllWrite : false,
        board_access: inviteScope === "custom" ? inviteAccessList : [],
      },
    });
  };

  const handleCopyInvite = async (invite: OrganizationInviteRead) => {
    try {
      const baseUrl =
        typeof window !== "undefined" ? window.location.origin : "";
      const inviteUrl = baseUrl
        ? `${baseUrl}/invite?token=${invite.token}`
        : invite.token;
      let copied = false;

      if (typeof navigator !== "undefined" && navigator.clipboard) {
        try {
          await navigator.clipboard.writeText(inviteUrl);
          copied = true;
        } catch {
          copied = false;
        }
      }

      if (!copied && typeof document !== "undefined") {
        const textarea = document.createElement("textarea");
        textarea.value = inviteUrl;
        textarea.setAttribute("readonly", "true");
        textarea.style.position = "absolute";
        textarea.style.left = "-9999px";
        document.body.appendChild(textarea);
        textarea.select();
        copied = document.execCommand("copy");
        document.body.removeChild(textarea);
      }

      if (copied) {
        setCopiedInviteId(invite.id);
        setTimeout(() => setCopiedInviteId(null), 2000);
        return;
      }

      if (typeof window !== "undefined") {
        window.prompt("Copy invite link:", inviteUrl);
      }
    } catch {
      setCopiedInviteId(null);
    }
  };

  const openAccessDialog = (memberId: string) => {
    setActiveMemberId(memberId);
    setAccessDialogOpen(true);
    resetAccessState();
  };

  const handleSaveAccess = async () => {
    if (!activeMemberId || !isAdmin) return;

    const hasAllAccess =
      resolvedAccessScope === "all" &&
      (resolvedAccessAllRead || resolvedAccessAllWrite);
    const accessList = buildAccessList(resolvedAccessMap);
    const hasCustomAccess =
      resolvedAccessScope === "custom" && accessList.length > 0;

    if (!hasAllAccess && !hasCustomAccess) {
      setAccessError("Select read or write access for at least one board.");
      return;
    }

    setAccessError(null);

    try {
      if (memberDetails) {
        if (memberDetails.role !== resolvedAccessRole) {
          await updateMemberRoleMutation.mutateAsync({
            memberId: memberDetails.id,
            data: { role: resolvedAccessRole },
          });
        }
      }

      await updateMemberAccessMutation.mutateAsync({
        memberId: activeMemberId,
        data: {
          all_boards_read:
            resolvedAccessScope === "all" ? resolvedAccessAllRead : false,
          all_boards_write:
            resolvedAccessScope === "all" ? resolvedAccessAllWrite : false,
          board_access: resolvedAccessScope === "custom" ? accessList : [],
        },
      });

      setAccessDialogOpen(false);
    } catch (err) {
      setAccessError(
        err instanceof Error ? err.message : "Unable to update member access.",
      );
    }
  };

  const handleDeleteOrganization = () => {
    if (!isOwner) return;
    deleteOrganizationMutation.mutate();
  };

  const activeMemberCanBeRemoved =
    isAdmin &&
    memberDetails !== null &&
    memberDetails.user_id !== membershipQuery.data?.data.user_id &&
    (isOwner || memberDetails.role !== "owner");

  const handleRemoveMember = () => {
    if (!activeMemberId || !activeMemberCanBeRemoved) return;
    removeMemberMutation.mutate({ memberId: activeMemberId });
  };

  const memberAccessSummary = (member: OrganizationMemberRead) =>
    summarizeAccess(member.all_boards_read, member.all_boards_write);

  const memberDisplay = (member: OrganizationMemberRead) => {
    const primary =
      member.user?.name ||
      member.user?.preferred_name ||
      member.user?.email ||
      member.user_id;
    const secondary = member.user?.email ?? "No email on file";
    return {
      primary,
      secondary,
      initials: initialsFrom(primary),
    };
  };

  return (
    <DashboardShell>
      <SignedOut>
        <SignedOutPanel
          message="Sign in to manage your organization."
          forceRedirectUrl="/organization"
          signUpForceRedirectUrl="/organization"
        />
      </SignedOut>
      <SignedIn>
        <DashboardSidebar />
        <main className="flex-1 overflow-y-auto bg-slate-50">
          <div className="sticky top-0 z-30 border-b border-slate-200 bg-white">
            <div className="px-8 py-6">
              <div className="flex flex-wrap items-center justify-between gap-6">
                <div>
                  <div className="flex flex-wrap items-center gap-3">
                    <h1 className="text-2xl font-semibold tracking-tight text-slate-900">
                      Organization
                    </h1>
                    <Badge
                      variant="outline"
                      className="flex items-center gap-2"
                    >
                      <Building2 className="h-3.5 w-3.5" />
                      {orgName}
                    </Badge>
                  </div>
                  <p className="mt-1 text-sm text-slate-500">
                    Manage members and board access across your workspace.
                  </p>
                  <div className="mt-3 flex flex-wrap items-center gap-4 text-xs text-slate-500">
                    <span>
                      <strong className="text-slate-900">
                        {members.length}
                      </strong>{" "}
                      members
                    </span>
                    <span>
                      <strong className="text-slate-900">
                        {boards.length}
                      </strong>{" "}
                      boards
                    </span>
                    <span>
                      <strong className="text-slate-900">
                        {invites.length}
                      </strong>{" "}
                      pending
                    </span>
                  </div>
                </div>
                <div className="flex flex-wrap items-center gap-2">
                  {isOwner ? (
                    <Button
                      type="button"
                      variant="outline"
                      className="border-rose-200 text-rose-600 hover:border-rose-300 hover:text-rose-700"
                      onClick={() => {
                        deleteOrganizationMutation.reset();
                        setDeleteOrgOpen(true);
                      }}
                    >
                      Delete organization
                    </Button>
                  ) : null}
                  <Button
                    type="button"
                    onClick={() => setInviteDialogOpen(true)}
                    disabled={!isAdmin}
                    title={
                      isAdmin ? undefined : "Only organization admins can invite"
                    }
                  >
                    <UserPlus className="h-4 w-4" />
                    Invite member
                  </Button>
                </div>
              </div>
            </div>
          </div>

          <div className="px-8 py-8">
            <div className="overflow-hidden rounded-2xl border border-slate-200 bg-white">
              <div className="flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 px-5 py-4">
                <div>
                  <h2 className="text-sm font-semibold text-slate-900">
                    Members & invites
                  </h2>
                  <p className="text-xs text-slate-500">
                    Invite teammates and tune their board permissions.
                  </p>
                </div>
                <div className="flex items-center gap-2 text-xs text-slate-500">
                  <Users className="h-4 w-4" />
                  {members.length + invites.length} total
                </div>
              </div>
              <div className="overflow-x-auto">
                <table className="min-w-full text-sm">
                  <thead className="bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500">
                    <tr>
                      <th className="px-5 py-3 text-left font-medium">
                        Member
                      </th>
                      <th className="px-5 py-3 text-left font-medium">
                        Status
                      </th>
                      <th className="px-5 py-3 text-left font-medium">
                        Access
                      </th>
                      <th className="px-5 py-3 text-right font-medium">
                        Actions
                      </th>
                    </tr>
                  </thead>
                  <tbody>
                    {membersQuery.isLoading ? (
                      <tr>
                        <td
                          colSpan={4}
                          className="px-5 py-6 text-center text-sm text-slate-500"
                        >
                          Loading members...
                        </td>
                      </tr>
                    ) : null}

                    {members.map((member) => {
                      const display = memberDisplay(member);
                      return (
                        <tr
                          key={member.id}
                          className="border-t border-slate-200 hover:bg-slate-50"
                        >
                          <td className="px-5 py-4">
                            <div className="flex items-center gap-3">
                              <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-500 text-xs font-semibold text-white">
                                {display.initials}
                              </div>
                              <div>
                                <div className="text-sm font-semibold text-slate-900">
                                  {display.primary}
                                </div>
                                <div className="text-xs text-slate-500">
                                  {display.secondary}
                                </div>
                              </div>
                            </div>
                          </td>
                          <td className="px-5 py-4">
                            <Badge variant={roleBadgeVariant(member.role)}>
                              {member.role}
                            </Badge>
                          </td>
                          <td className="px-5 py-4 text-slate-600">
                            {memberAccessSummary(member)}
                          </td>
                          <td className="px-5 py-4 text-right">
                            {isAdmin ? (
                              <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                onClick={() => openAccessDialog(member.id)}
                              >
                                Manage access
                              </Button>
                            ) : (
                              <span className="text-xs text-slate-400">
                                Admin only
                              </span>
                            )}
                          </td>
                        </tr>
                      );
                    })}

                    {isAdmin && invitesQuery.isLoading ? (
                      <tr>
                        <td
                          colSpan={4}
                          className="px-5 py-6 text-center text-sm text-slate-500"
                        >
                          Loading invites...
                        </td>
                      </tr>
                    ) : null}

                    {isAdmin
                      ? invites.map((invite) => (
                          <tr
                            key={invite.id}
                            className="border-t border-slate-200 bg-slate-50/60"
                          >
                            <td className="px-5 py-4">
                              <div className="flex items-center gap-3">
                                <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-slate-200 text-xs font-semibold text-slate-600">
                                  {initialsFrom(invite.invited_email)}
                                </div>
                                <div>
                                  <div className="text-sm font-semibold text-slate-900">
                                    {invite.invited_email}
                                  </div>
                                  <div className="text-xs text-slate-500">
                                    Invited {formatTimestamp(invite.created_at)}
                                  </div>
                                </div>
                              </div>
                            </td>
                            <td className="px-5 py-4">
                              <div className="flex flex-wrap items-center gap-2">
                                <Badge variant="warning">Pending</Badge>
                                <Badge variant={roleBadgeVariant(invite.role)}>
                                  {invite.role}
                                </Badge>
                              </div>
                            </td>
                            <td className="px-5 py-4 text-slate-600">
                              {summarizeAccess(
                                invite.all_boards_read,
                                invite.all_boards_write,
                              )}
                            </td>
                            <td className="px-5 py-4 text-right">
                              <div className="flex flex-wrap items-center justify-end gap-2">
                                <Button
                                  type="button"
                                  variant="outline"
                                  size="sm"
                                  onClick={() => handleCopyInvite(invite)}
                                >
                                  <Copy className="h-4 w-4" />
                                  {copiedInviteId === invite.id
                                    ? "Copied"
                                    : "Copy link"}
                                </Button>
                                <Button
                                  type="button"
                                  variant="ghost"
                                  size="sm"
                                  onClick={() =>
                                    revokeInviteMutation.mutate({
                                      inviteId: invite.id,
                                    })
                                  }
                                  disabled={revokeInviteMutation.isPending}
                                >
                                  Revoke
                                </Button>
                              </div>
                            </td>
                          </tr>
                        ))
                      : null}

                    {!membersQuery.isLoading &&
                    (!isAdmin || !invitesQuery.isLoading) &&
                    members.length === 0 &&
                    (!isAdmin || invites.length === 0) ? (
                      <tr>
                        <td
                          colSpan={4}
                          className="px-5 py-6 text-center text-sm text-slate-500"
                        >
                          No members or invites yet.
                        </td>
                      </tr>
                    ) : null}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </main>
      </SignedIn>

      <Dialog open={inviteDialogOpen} onOpenChange={handleInviteDialogChange}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Invite a member</DialogTitle>
            <DialogDescription>
              Grant access to all boards or select specific workspaces.
            </DialogDescription>
          </DialogHeader>

          {isAdmin ? (
            <form className="space-y-5" onSubmit={handleInviteSubmit}>
              <div className="grid gap-4 sm:grid-cols-[1fr_200px]">
                <div className="space-y-2">
                  <label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
                    Email address
                  </label>
                  <Input
                    value={inviteEmail}
                    onChange={(event) => setInviteEmail(event.target.value)}
                    placeholder="name@company.com"
                    type="email"
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
                    Role
                  </label>
                  <Select value={inviteRole} onValueChange={setInviteRole}>
                    <SelectTrigger>
                      <SelectValue placeholder="Select role" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="member">Member</SelectItem>
                      <SelectItem value="admin">Admin</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
              </div>

              <BoardAccessEditor
                boards={boards}
                scope={inviteScope}
                onScopeChange={setInviteScope}
                allRead={inviteAllRead}
                allWrite={inviteAllWrite}
                onAllReadChange={setInviteAllRead}
                onAllWriteChange={setInviteAllWrite}
                access={inviteAccess}
                onAccessChange={setInviteAccess}
                emptyMessage={
                  boardsQuery.isLoading
                    ? "Loading boards..."
                    : "Create a board to start assigning access."
                }
              />

              {inviteError ? (
                <p className="text-sm text-rose-500">{inviteError}</p>
              ) : null}

              <DialogFooter>
                <Button
                  type="button"
                  variant="outline"
                  onClick={() => setInviteDialogOpen(false)}
                >
                  Cancel
                </Button>
                <Button type="submit" disabled={createInviteMutation.isPending}>
                  {createInviteMutation.isPending
                    ? "Sending invite..."
                    : "Send invite"}
                </Button>
              </DialogFooter>
            </form>
          ) : (
            <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
              Only organization admins can invite new members.
            </div>
          )}
        </DialogContent>
      </Dialog>

      <Dialog open={accessDialogOpen} onOpenChange={handleAccessDialogChange}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Manage member access</DialogTitle>
            <DialogDescription>
              Adjust board permissions and role for this teammate.
            </DialogDescription>
          </DialogHeader>

          {memberDetailsQuery.isLoading ? (
            <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
              Loading member access...
            </div>
          ) : memberDetailsQuery.data?.status === 200 ? (
            <div className="space-y-6">
              <div className="rounded-xl border border-slate-200 bg-white px-5 py-4">
                <p className="text-sm font-semibold text-slate-900">
                  {memberDetailsQuery.data.data.user?.name ||
                    memberDetailsQuery.data.data.user?.preferred_name ||
                    memberDetailsQuery.data.data.user?.email ||
                    memberDetailsQuery.data.data.user_id}
                </p>
                <p className="mt-1 text-xs text-slate-500">
                  {memberDetailsQuery.data.data.user?.email ??
                    "No email on file"}
                </p>
              </div>

              <div className="space-y-3">
                <label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
                  Role
                </label>
                <Select
                  value={resolvedAccessRole}
                  onValueChange={setAccessRole}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select role" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="owner">Owner</SelectItem>
                    <SelectItem value="member">Member</SelectItem>
                    <SelectItem value="admin">Admin</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              <BoardAccessEditor
                boards={boards}
                scope={resolvedAccessScope}
                onScopeChange={setAccessScope}
                allRead={resolvedAccessAllRead}
                allWrite={resolvedAccessAllWrite}
                onAllReadChange={setAccessAllRead}
                onAllWriteChange={setAccessAllWrite}
                access={resolvedAccessMap}
                onAccessChange={setAccessMap}
                emptyMessage={
                  boardsQuery.isLoading ? "Loading boards..." : undefined
                }
              />

              {accessError ? (
                <p className="text-sm text-rose-500">{accessError}</p>
              ) : null}
            </div>
          ) : (
            <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
              Unable to load member access.
            </div>
          )}

          <DialogFooter className="pt-2">
            {activeMemberCanBeRemoved ? (
              <Button
                type="button"
                variant="outline"
                className="mr-auto border-rose-200 text-rose-600 hover:border-rose-300 hover:text-rose-700"
                onClick={() => {
                  removeMemberMutation.reset();
                  setRemoveMemberOpen(true);
                }}
              >
                Remove member
              </Button>
            ) : null}
            <Button
              type="button"
              variant="outline"
              onClick={() => setAccessDialogOpen(false)}
            >
              Cancel
            </Button>
            <Button
              type="button"
              onClick={handleSaveAccess}
              disabled={
                updateMemberAccessMutation.isPending ||
                updateMemberRoleMutation.isPending ||
                removeMemberMutation.isPending
              }
            >
              {updateMemberAccessMutation.isPending ||
              updateMemberRoleMutation.isPending
                ? "Saving..."
                : "Save changes"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      <ConfirmActionDialog
        open={deleteOrgOpen}
        onOpenChange={(open) => {
          setDeleteOrgOpen(open);
          if (!open) {
            deleteOrganizationMutation.reset();
          }
        }}
        ariaLabel="Delete organization"
        title="Delete organization"
        description={
          <>
            This will permanently delete <strong>{orgName}</strong>, including
            boards, groups, gateways, members, and invites. This action cannot
            be undone.
          </>
        }
        errorMessage={deleteOrganizationMutation.error?.message}
        onConfirm={handleDeleteOrganization}
        isConfirming={deleteOrganizationMutation.isPending}
        confirmLabel="Delete organization"
        confirmingLabel="Deleting…"
      />
      <ConfirmActionDialog
        open={removeMemberOpen}
        onOpenChange={(open) => {
          setRemoveMemberOpen(open);
          if (!open) {
            removeMemberMutation.reset();
          }
        }}
        ariaLabel="Remove organization member"
        title="Remove member"
        description={
          <>
            Remove{" "}
            <strong>
              {memberDetails?.user?.name ||
                memberDetails?.user?.preferred_name ||
                memberDetails?.user?.email ||
                "this member"}
            </strong>{" "}
            from <strong>{orgName}</strong>? They will lose access immediately.
          </>
        }
        errorMessage={removeMemberMutation.error?.message}
        onConfirm={handleRemoveMember}
        isConfirming={removeMemberMutation.isPending}
        confirmLabel="Remove member"
        confirmingLabel="Removing…"
      />
    </DashboardShell>
  );
}
