"use client";

import { useMemo, useState } from "react";
import { Search } from "lucide-react";
import { toast } from "sonner";

import type { PortalAppCatalog } from "@/app/dashboard/customers/_lib/portal-routes-server-api";
import { PortalPermissionTree } from "@/components/admins/portal/portal-permission-tree";
import { ErrorBanner } from "@/components/shared/error-banner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { FRONTEND_ROUTES } from "@/config/frontend-routes";
import { submitDashboardForm } from "@/lib/dashboard-mutations.client";
import { useChanged } from "@/hooks/use-changed";
import { toastApiError } from "@/lib/toast-api-error";
import { hideTransactionsMutateActions } from "@/lib/portal-permission-catalog";

type CustomerPortalRoutesFormProps = {
  customerId: number;
  customerName?: string | null;
  apps: PortalAppCatalog[];
  initialRoutes: string[];
  hasConfiguredEntitlements: boolean;
  preferRolesGroupLabels?: boolean;
  /** Kept for caller compatibility; Transactions is a single combined list now. */
  accountType?: string | null;
  initialErrorMessage?: string | null;
  onSuccess?: () => void;
};

export function CustomerPortalRoutesForm({
  customerId,
  apps,
  initialRoutes,
  hasConfiguredEntitlements,
  preferRolesGroupLabels = false,
  initialErrorMessage,
  onSuccess,
}: CustomerPortalRoutesFormProps) {
  const otherApps = useMemo(() => apps.filter((app) => app.app !== "transactions"), [apps]);
  const transactionsApps = useMemo(
    () => hideTransactionsMutateActions(apps.filter((app) => app.app === "transactions")),
    [apps],
  );

  const catalogApps = useMemo(
    () => [...transactionsApps, ...otherApps],
    [transactionsApps, otherApps],
  );

  const allRoutes = useMemo(
    () =>
      catalogApps.flatMap((app) =>
        app.groups.flatMap((group) => group.routes.map((route) => route.route)),
      ),
    [catalogApps],
  );

  const resolvedInitialRoutes = useMemo(() => {
    const visible = new Set(allRoutes);
    if (initialRoutes.length > 0) {
      return initialRoutes.filter((route) => visible.has(route));
    }
    if (!hasConfiguredEntitlements) {
      return allRoutes;
    }
    return [];
  }, [allRoutes, hasConfiguredEntitlements, initialRoutes]);

  const [selectedRoutes, setSelectedRoutes] = useState<string[]>(resolvedInitialRoutes);
  const [isSaving, setIsSaving] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");

  // Reset the selection when we switch customer or the server sends new routes.
  // Both hooks must run every render, so evaluate them before branching.
  const customerChanged = useChanged(customerId);
  const routesChanged = useChanged(resolvedInitialRoutes);
  if (customerChanged || routesChanged) {
    setSelectedRoutes(resolvedInitialRoutes);
  }

  async function handleSave() {
    setIsSaving(true);
    try {
      const message = await submitDashboardForm({
        mode: "update",
        id: customerId,
        values: { routes: selectedRoutes },
        createUrl: FRONTEND_ROUTES.customers.portalRoutesSubmit,
        updateUrl: FRONTEND_ROUTES.customers.portalRoutesSubmit,
        messages: {
          createFail: "Portal route entitlements could not be saved.",
          updateFail: "Portal route entitlements could not be saved.",
          createSuccess: "Portal route entitlements updated.",
          updateSuccess: "Portal route entitlements updated.",
        },
      });
      toast.success(message);
      onSuccess?.();
    } catch (error) {
      toastApiError(error, "Portal route entitlements could not be saved.");
    } finally {
      setIsSaving(false);
    }
  }

  if (initialErrorMessage) {
    return <ErrorBanner message={initialErrorMessage} />;
  }

  const selectedCount = selectedRoutes.length;
  const totalCount = allRoutes.length;

  return (
    <div className="flex min-h-0 flex-col gap-4">
      <div className="space-y-3">
        <p className="rounded-lg border bg-muted/40 px-3 py-2.5 text-muted-foreground text-xs leading-relaxed">
          This sheet is the <span className="font-medium text-foreground">ceiling</span>{" "}
          (what platform sold this account). The corporate owner uses{" "}
          <span className="font-medium text-foreground">Admin → Roles</span> to grant subsets of
          these routes to RMs, portal users, and customers — they cannot grant routes that are
          unchecked here.
        </p>

        <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
          <div className="relative min-w-0 flex-1 sm:max-w-sm">
            <Search className="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground" />
            <Input
              value={searchQuery}
              onChange={(event) => setSearchQuery(event.target.value)}
              placeholder="Search modules…"
              className="h-9 bg-card pl-8"
              aria-label="Search portal permissions"
            />
          </div>
          <p className="shrink-0 text-xs tabular-nums text-muted-foreground">
            <span className="font-medium text-foreground">{selectedCount}</span> of {totalCount}{" "}
            routes selected
            {transactionsApps.length > 0 ? (
              <span className="text-muted-foreground/80">
                {" "}
                · Transactions show View only
              </span>
            ) : null}
          </p>
        </div>
      </div>

      <PortalPermissionTree
        apps={catalogApps}
        selectedRoutes={selectedRoutes}
        onSelectedRoutesChange={setSelectedRoutes}
        preferRolesGroupLabels={preferRolesGroupLabels}
        searchQuery={searchQuery}
      />

      <div className="sticky bottom-0 z-10 -mx-5 mt-1 flex items-center justify-end gap-2 border-t bg-card/95 px-5 py-3 backdrop-blur supports-backdrop-filter:bg-card/80 sm:-mx-6 sm:px-6">
        <Button
          type="button"
          variant="outline"
          size="sm"
          onClick={() => onSuccess?.()}
          disabled={isSaving}
        >
          Cancel
        </Button>
        <Button type="button" size="sm" onClick={() => void handleSave()} disabled={isSaving}>
          {isSaving ? "Saving…" : "Save entitlements"}
        </Button>
      </div>
    </div>
  );
}
