import Link from "next/link";
import { Suspense } from "react";

import { getRoles } from "@/actions/roles/roles";
import { getCurrentUserTenantRole, getUsers } from "@/actions/users/users";
import { auth } from "@/auth.config";
import { Button } from "@/components/shadcn";
import { ContentLayout } from "@/components/shadcn/content-layout";
import { DataTable } from "@/components/shadcn/table";
import { ColumnsUser, SkeletonTableUser } from "@/components/users/table";
import { Role, SearchParamsProps, UserProps } from "@/types";
import { TENANT_MEMBERSHIP_ROLE } from "@/types/users";

export default async function Users({
  searchParams,
}: {
  searchParams: Promise<SearchParamsProps>;
}) {
  const resolvedSearchParams = await searchParams;
  const searchParamsKey = JSON.stringify(resolvedSearchParams || {});

  return (
    <ContentLayout title="Users" icon="lucide:user">
      <div className="flex flex-col gap-6">
        <div className="flex flex-row items-end justify-end">
          <Button asChild>
            <Link href="/invitations/new">Invite User</Link>
          </Button>
        </div>

        <Suspense key={searchParamsKey} fallback={<SkeletonTableUser />}>
          <SSRDataTable searchParams={resolvedSearchParams} />
        </Suspense>
      </div>
    </ContentLayout>
  );
}

const SSRDataTable = async ({
  searchParams,
}: {
  searchParams: SearchParamsProps;
}) => {
  const page = parseInt(searchParams.page?.toString() || "1", 10);
  const sort = searchParams.sort?.toString();
  const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10);

  // Extract all filter parameters
  const filters = Object.fromEntries(
    Object.entries(searchParams).filter(([key]) => key.startsWith("filter[")),
  );

  // Extract query from filters
  const query = (filters["filter[search]"] as string) || "";

  const [usersData, rolesData, currentTenantRole, session] = await Promise.all([
    getUsers({ query, page, sort, filters, pageSize }),
    getRoles({}),
    getCurrentUserTenantRole(),
    auth(),
  ]);

  const currentUserId = session?.userId;
  const currentTenantId = session?.tenantId;
  const isCurrentUserOwner = currentTenantRole === TENANT_MEMBERSHIP_ROLE.Owner;

  // Create a dictionary for roles by user ID
  const roleDict: Record<string, Role["attributes"]> = {};
  for (const item of (usersData?.included || []) as Role[]) {
    if (item.type === "roles") {
      roleDict[item.id] = item.attributes;
    }
  }

  // Generate the array of roles with all the roles available
  const roles = Array.from(
    new Map(
      (rolesData?.data || []).map((role: Role) => [
        role.id,
        { id: role.id, name: role.attributes?.name || "Unnamed Role" },
      ]),
    ).values(),
  );

  // Expand the users with their roles
  const expandedUsers = (usersData?.data || []).map((user: UserProps) => {
    // Check if the user has a role
    const roleId = user?.relationships?.roles?.data?.[0]?.id;
    const role = roleDict?.[roleId] || null;

    // Gate the "Expel" action server-side: only tenant owners may expel,
    // and never against themselves (self-leave lives elsewhere).
    const canBeExpelled =
      isCurrentUserOwner && !!currentTenantId && user.id !== currentUserId;

    return {
      ...user,
      attributes: {
        ...(user?.attributes || {}),
        role,
      },
      roles,
      canBeExpelled,
      currentTenantId: canBeExpelled ? currentTenantId : undefined,
      // Users may only delete their own account; gate the delete action so the
      // UI matches the backend rule and never offers an action that would fail.
      isCurrentUser: user.id === currentUserId,
    };
  });

  return (
    <DataTable
      key={`scans-${Date.now()}`}
      columns={ColumnsUser}
      data={expandedUsers || []}
      metadata={usersData?.meta}
      showSearch
    />
  );
};
