import BreadCrumbLink from "@/layouts/shared/page.breadcrumbLink";
import { Alert } from "@mantine/core";
import { IconAlertTriangle } from "@tabler/icons-react";
import {
  getMyMemberAccess,
  NO_MEMBER_ACCESS,
  type MemberAccess,
} from "@/lib/features/members/access";
import { isSuperAdminAccess } from "@/lib/role-helpers";
import { getBookingsByMembership } from "@/lib/features/bookings/query";
import { searchCuratedEventBookings } from "@/lib/features/bookings/curated/query";
import type { CuratedEventsBooking } from "@/lib/features/bookings/curated/types";
import type { CoreBookingUnit } from "@/lib/features/bookings/types";
import {
  getAccountOverview,
  getMemberShipContacts,
  getMembershipDetails,
} from "@/lib/features/members/query";
import type { CoreAccountOverview } from "@/lib/features/members/query";
import type {
  CoreMemberDetailed,
  VpAccountDetails,
} from "@/lib/features/members/types";
import type { CoreAPIPagination, CoreResponse } from "@/lib/features/types";
import type { Route } from "../../../layouts/+types/members.layout";
import MemberClientPage from "./_client";

export const handle = {
  breadcrumb: ({ params }: { params: { accountId: string } }) => (
    <BreadCrumbLink
      links={[
        {
          label: "Accounts",
          to: "/admin/members",
        },
        {
          label: params.accountId,
        },
      ]}
    />
  ),
};

export async function loader({ request, params }: Route.LoaderArgs) {
  const accountId = (params as { accountId: string }).accountId;
  const url = new URL(request.url);
  const page = parseInt(url.searchParams.get("page") ?? "1", 10) || 1;
  const pageSize = parseInt(url.searchParams.get("pageSize") ?? "15", 10) || 15;

  /*
   * Promo context, when the user arrived from a promo-code drilldown.
   *
   * Those pages redirect here instead of embedding a second copy of this page,
   * and pass what only they know: where to go back to, and the reward points the
   * code allocated to this member.
   */
  const fromHref = url.searchParams.get("from") ?? undefined;
  const fromLabel = url.searchParams.get("fromLabel") ?? undefined;
  const pointsParam = Number.parseInt(url.searchParams.get("points") ?? "", 10);
  const pointsAllocated = Number.isFinite(pointsParam) ? pointsParam : null;

  const requestedType = url.searchParams.get("type");
  const bookingEntityType: "internal" | "external" | "curated" =
    requestedType === "external" || requestedType === "curated"
      ? requestedType
      : "internal";

  const headers = { Cookie: request.headers.get("Cookie") ?? "" };
  // Capabilities come from the member module's own access record, not console
  // roles. Skip the fetches the user isn't allowed rather than calling and 403ing.
  const accessRes = await getMyMemberAccess(headers);
  const memberAccess = accessRes?.success
    ? (accessRes.data as MemberAccess)
    : NO_MEMBER_ACCESS;
  const canViewBookings = memberAccess.can_view_bookings;
  const canViewOverview = memberAccess.can_view_analytics;
  /*
   * Deletion is a console-role capability, not a member-module one.
   *
   * Decided here rather than in the client from the `admin_scopes` cookie, because
   * the client-side check has no cookie during the server render and returns false
   * — which left the Delete button and the Deletion tab out of the server HTML and
   * dependent on a hydration pass to appear at all. The loader has the request, so
   * the answer is the same on both sides of the render.
   */
  const canDeleteAccount = isSuperAdminAccess(request);

  const membershipRes = await getMembershipDetails(accountId, headers);
  if (!membershipRes?.success) {
    // Return the reason: an empty object rendered a blank page with no account
    // number and no explanation, which looks identical to a page still loading.
    return {
      loadError:
        membershipRes?.message ||
        `Couldn't load member #${accountId}. The account lookup failed.`,
    };
  }
  const realId = membershipRes.data?.account?.AccountID as string;
  const [
    contactsResponse,
    internalBookings,
    externalBookings,
    curatedBookings,
  ] = await Promise.all([
    getMemberShipContacts(realId, headers),
    canViewBookings
      ? getBookingsByMembership(page, pageSize, realId, request, "internal")
      : undefined,
    canViewBookings
      ? getBookingsByMembership(page, pageSize, realId, request, "external")
      : undefined,
    canViewBookings
      ? searchCuratedEventBookings(page, pageSize, realId, headers)
      : undefined,
  ]);
  // Aggregates last: they scan bookings and sessions on the member DB, which
  // has timed out before when heavy reads overlapped.
  const overviewResponse = canViewOverview
    ? await getAccountOverview(realId, headers)
    : undefined;

  return {
    membershipRes,
    contactsResponse,
    internalBookings,
    externalBookings,
    curatedBookings,
    bookingEntityType,
    canViewBookings,
    canViewPoints: memberAccess.can_view_points,
    canDeleteAccount,
    overviewResponse,
    fromHref,
    fromLabel,
    pointsAllocated,
  };
}

type BookingsResponse = CoreResponse<{
  bookings: CoreBookingUnit[];
  pagination: CoreAPIPagination;
}>;

const MemberPage: React.FC<Route.ComponentProps> = ({ loaderData }) => {
  const {
    loadError,
    membershipRes,
    contactsResponse,
    internalBookings,
    externalBookings,
    curatedBookings,
    bookingEntityType,
    canViewBookings,
    canViewPoints,
    canDeleteAccount,
    overviewResponse,
    fromHref,
    fromLabel,
    pointsAllocated,
  } = loaderData as unknown as {
    loadError?: string;
    membershipRes: CoreResponse<{ account: VpAccountDetails }>;
    contactsResponse: CoreResponse<{ members: CoreMemberDetailed[] }>;
    internalBookings?: BookingsResponse;
    externalBookings?: BookingsResponse;
    curatedBookings?: CoreResponse<{
      bookings: CuratedEventsBooking[];
      pagination: CoreAPIPagination;
    }>;
    bookingEntityType?: "internal" | "external" | "curated";
    canViewBookings?: boolean;
    canViewPoints?: boolean;
    canDeleteAccount?: boolean;
    overviewResponse?: CoreResponse<CoreAccountOverview>;
    fromHref?: string;
    fromLabel?: string;
    pointsAllocated?: number | null;
  };
  if (loadError) {
    return (
      <Alert
        color="red"
        variant="light"
        title="Member unavailable"
        icon={<IconAlertTriangle size={16} />}
        mx={28}
      >
        {loadError}
      </Alert>
    );
  }

  return (
    <MemberClientPage
      account={membershipRes?.data?.account ?? ({} as VpAccountDetails)}
      contacts={contactsResponse?.data?.members ?? []}
      bookingsByType={{
        internal: {
          data: internalBookings?.data?.bookings ?? [],
          totalRows: internalBookings?.data?.pagination?.total ?? 0,
        },
        external: {
          data: externalBookings?.data?.bookings ?? [],
          totalRows: externalBookings?.data?.pagination?.total ?? 0,
        },
      }}
      curatedBookings={{
        data: curatedBookings?.data?.bookings ?? [],
        totalRows: curatedBookings?.data?.pagination?.total ?? 0,
      }}
      bookingEntityType={bookingEntityType ?? "internal"}
      canViewBookings={Boolean(canViewBookings)}
      canViewPoints={Boolean(canViewPoints)}
      canDeleteAccount={Boolean(canDeleteAccount)}
      pointsAllocated={pointsAllocated}
      backHref={fromHref}
      backLabel={fromLabel}
      overview={overviewResponse?.success ? overviewResponse.data : undefined}
    />
  );
};

export default MemberPage;
