import BreadCrumbLink from "@/layouts/shared/page.breadcrumbLink";
import type {
  AccessScope,
  CoreAPIPagination,
  CoreResponse,
} from "@/lib/features/types";
import { getAdminUsers } from "@/lib/features/users/query";
import { getAdminRoles } from "@/lib/features/users/roles/query";
import type { AdminRole } from "@/lib/features/users/roles/types";
import type { AdminUser } from "@/lib/features/users/types";
import { FEATURE_SLUGS, getCheckedAccess } from "@/lib/role-helpers";
import UsersClientPage from "./_client";
import { createRoleProtectedLoader } from "@/lib/features/protectedFetcher";
import type { Route } from "./+types/page";

export const handle = {
  breadcrumb: () => (
    <BreadCrumbLink
      links={[
        {
          label: "Users",
        },
        {
          label: "Overview",
        },
      ]}
    />
  ),
};

export const loader = createRoleProtectedLoader(
  FEATURE_SLUGS.userManagement,
  "read",
  async ({ request }) => {
    const url = new URL(request.url);
    const page = parseInt(url.searchParams.get("page") ?? "1");
    // Matches the table's own fallback. They disagreed (15 here, 50 there), so the
    // first paint fetched 15 rows while the pager said 50 and immediately refetched.
    const pageSize = parseInt(url.searchParams.get("pageSize") ?? "50");
    const search = url.searchParams.get("search") ?? undefined;

    // Filters live in the URL so the server does the filtering and the view is
    // shareable — the same arrangement as the members list.
    const roleIds = (url.searchParams.get("roleIds") ?? "")
      .split(",")
      .map((id) => id.trim())
      .filter(Boolean);
    /*
     * Active users only, unless asked otherwise.
     *
     * Deactivated accounts are kept for the audit trail, so they accumulate and
     * would otherwise pad the list with people who cannot sign in. "all" is the
     * explicit opt-in; an absent param means the default, not "no filter".
     */
    const isActiveParam = url.searchParams.get("isActive") ?? "true";
    const superOnly = url.searchParams.get("superAdmin") === "true";
    const filters = {
      roleIds,
      isActive:
        isActiveParam === "true"
          ? true
          : isActiveParam === "false"
            ? false
            : undefined,
      isSuperAdmin: superOnly ? true : undefined,
    };

    const [adminUsers, roles] = await Promise.all([
      getAdminUsers(page, pageSize, search, request, filters),
      // Options for the role filter; the list itself is small.
      getAdminRoles(1, 200, undefined, request),
    ]);
    const accessScope = getCheckedAccess(request, FEATURE_SLUGS.userManagement);
    return {
      adminUsers,
      accessScope,
      roles,
      filters: {
        ...filters,
        searchTerm: search ?? "",
        superOnly,
        showAll: isActiveParam === "all",
      },
    };
  },
);

const UsersPage: React.FC<Route.ComponentProps> = ({ loaderData }) => {
  const { adminUsers, accessScope, roles, filters } = loaderData as unknown as {
    adminUsers: CoreResponse<{
      users: AdminUser[];
      pagination: CoreAPIPagination;
    }>;
    accessScope: AccessScope;
    roles?: CoreResponse<{ roles: AdminRole[] }>;
    filters: {
      searchTerm: string;
      roleIds: string[];
      isActive?: boolean;
      superOnly: boolean;
      showAll: boolean;
    };
  };

  return (
    <UsersClientPage
      tableProps={{
        data: adminUsers?.data?.users ?? [],
        totalRows: adminUsers?.data?.pagination?.total ?? 0,
      }}
      accessScope={accessScope}
      roles={(roles?.data?.roles ?? []).map((role) => ({
        value: String(role.id),
        label: role.name,
      }))}
      filters={{
        searchTerm: filters?.searchTerm ?? "",
        roleIds: filters?.roleIds ?? [],
        activeOnly: filters?.isActive === true,
        inactiveOnly: filters?.isActive === false,
        includeInactive: Boolean(filters?.showAll),
        superAdminsOnly: Boolean(filters?.superOnly),
      }}
    />
  );
};

export default UsersPage;
