"use client";

import * as React from "react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";

import { ArrowLeft, Layers3 } from "lucide-react";
import { toast } from "sonner";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import type { StockAccumulatorFormValues } from "@/components/form/schemas/stock-accumulator-schema";
import type { StockOptionFormValues } from "@/components/form/schemas/stock-option-schema";
import type { StockSaleChildFormValues } from "@/components/form/schemas/stock-sale-schema";

export type ChildFormValues =
  | StockSaleChildFormValues
  | StockOptionFormValues
  | StockAccumulatorFormValues;

export type ChildFormComponentProps = {
  formId: string;
  initialValues?: ChildFormValues;
  fieldMeta?: unknown;
  formOptionsRaw?: Record<string, Record<string, string>>;
  onSubmit: (values: ChildFormValues) => void | Promise<void>;
};

export type ChildFormContextBase = {
  formName: string;
  model: Record<string, unknown>;
  formOptions: Record<string, Record<string, string>>;
  fieldMeta: unknown;
  meta?: {
    pageHeading?: string;
  };
  pid?: string;
};

export function childFormComponent(Component: unknown): React.ComponentType<ChildFormComponentProps> {
  return Component as React.ComponentType<ChildFormComponentProps>;
}

type FormComponentKind = "sale" | "option" | "accumulator";

/** Create-from-temp options a child form receives via the Temp Data impersonation `next=` target. */
export type ChildFormTempOptions = {
  tempId?: string;
  expiredId?: string;
  hide?: boolean;
};

export type ChildFormLoadOptions = ChildFormTempOptions & { markAsExpiredId?: string };

export type ChildFormRoutePageConfig<
  TKind extends string,
  TEditableKind extends TKind,
  TContext extends ChildFormContextBase,
> = {
  formId: string;
  childLabels: Record<TKind, string>;
  defaultTitle: string;
  parentEntityLabel: string;
  isChildKind: (value: string | null) => value is TKind;
  isEditableChildKind: (child: TKind | null) => child is TEditableKind;
  supportsStandaloneCreate: (child: TKind) => boolean;
  childFormIsReady?: (child: TKind | null, params: { pid: string; id: string }) => boolean;
  loadCreate: (child: TKind, pid: string, options: ChildFormLoadOptions) => Promise<TContext>;
  loadUpdate?: (child: TEditableKind, id: string, pid: string) => Promise<TContext>;
  create: (
    child: TKind,
    pid: string,
    values: Record<string, unknown>,
    formName: string,
    options: ChildFormLoadOptions,
  ) => Promise<void>;
  update?: (
    child: TEditableKind,
    id: string,
    pid: string,
    values: Record<string, unknown>,
    formName: string,
    context: TContext,
  ) => Promise<void>;
  mapModel: (child: TKind, context: TContext, pid: string) => ChildFormValues | undefined;
  formComponents: Record<FormComponentKind, React.ComponentType<ChildFormComponentProps>>;
  supportsMarkExpired?: boolean;
  useExplicitLoadingState?: boolean;
  rethrowSubmitError?: boolean;
  getBadgeLabel?: (isUpdateMode: boolean) => string;
  getParentPid?: (params: { pid: string; context: TContext | null }) => string | null;
  getFormKeySuffix?: (params: { id: string; pid: string }) => string;
  getMissingChildMessage?: (params: { child: TKind | null; loadError: string | null }) => string;
  isUpdateMode?: (params: { child: TKind | null; id: string }) => boolean;
};

function defaultChildFormIsReady<TKind extends string>(
  child: TKind | null,
  pid: string,
  supportsStandaloneCreate: (child: TKind) => boolean,
): boolean {
  if (!child) {
    return false;
  }
  if (pid) {
    return true;
  }

  return supportsStandaloneCreate(child);
}

function resolveFormComponentKind(child: string): FormComponentKind {
  if (child === "sale") {
    return "sale";
  }
  if (child === "option") {
    return "option";
  }

  return "accumulator";
}

export function createChildFormRoutePage<
  TKind extends string,
  TEditableKind extends TKind,
  TContext extends ChildFormContextBase,
>(config: ChildFormRoutePageConfig<TKind, TEditableKind, TContext>) {
  function ChildFormPage({ listPath }: { listPath: string }) {
    const router = useRouter();
    const searchParams = useSearchParams();
    const childParam = searchParams.get("child")?.trim() ?? "";
    const pid = searchParams.get("pid")?.trim() ?? "";
    const id = searchParams.get("id")?.trim() ?? "";
    const markAsExpiredId = searchParams.get("markAsExpired")?.trim() ?? "";
    const tempId = searchParams.get("temp_id")?.trim() ?? "";
    const expiredId = searchParams.get("expired_id")?.trim() ?? "";
    const hideFromTemp = searchParams.get("hide")?.trim() === "1";

    // Create-from-temp prefill (Temp Data → impersonate → `{module}/form?child=…&temp_id=…`).
    const tempOptions = React.useMemo<ChildFormTempOptions>(
      () => ({
        tempId: tempId || undefined,
        expiredId: expiredId || undefined,
        hide: hideFromTemp || undefined,
      }),
      [expiredId, hideFromTemp, tempId],
    );

    const [context, setContext] = React.useState<TContext | null>(null);
    const [initialValues, setInitialValues] = React.useState<ChildFormValues | undefined>(undefined);
    const [loadError, setLoadError] = React.useState<string | null>(null);
    const [isLoadingExplicit, setIsLoadingExplicit] = React.useState(config.useExplicitLoadingState ?? false);
    const [isSaving, setIsSaving] = React.useState(false);

    const child = config.isChildKind(childParam) ? childParam : null;
    const childFormIsReady =
      config.childFormIsReady ??
      ((currentChild, params) =>
        defaultChildFormIsReady(currentChild, params.pid, config.supportsStandaloneCreate));
    const canLoadForm = childFormIsReady(child, { pid, id });
    const isUpdateMode =
      config.isUpdateMode?.({ child, id }) ??
      (config.isEditableChildKind(child) && id !== "" && Boolean(config.update));

    React.useEffect(() => {
      if (!canLoadForm || !child) {
        if (config.useExplicitLoadingState) {
          setIsLoadingExplicit(false);
          setLoadError(null);
        }
        return;
      }

      let cancelled = false;

      if (config.useExplicitLoadingState) {
        setIsLoadingExplicit(true);
        setLoadError(null);
      }

      const markExpiredOptions =
        config.supportsMarkExpired && child === "mark_expired"
          ? { markAsExpiredId: markAsExpiredId || pid }
          : undefined;

      const loadPromise =
        isUpdateMode && config.loadUpdate && config.isEditableChildKind(child)
          ? config.loadUpdate(child, id, pid)
          : config.loadCreate(child, pid, { ...tempOptions, ...markExpiredOptions });

      void loadPromise
        .then((loaded) => {
          if (cancelled) return;
          setContext(loaded);
          setInitialValues(config.mapModel(child, loaded, pid));
          setLoadError(null);
        })
        .catch((error) => {
          if (cancelled) return;
          setLoadError(error instanceof Error ? error.message : "Could not load form.");
        })
        .finally(() => {
          if (!cancelled && config.useExplicitLoadingState) {
            setIsLoadingExplicit(false);
          }
        });

      return () => {
        cancelled = true;
      };
    }, [canLoadForm, child, id, isUpdateMode, markAsExpiredId, pid, tempOptions]);

    const title = child ? config.childLabels[child] : config.defaultTitle;
    const pageHeading = context?.meta?.pageHeading ?? title;
    const isLoading = config.useExplicitLoadingState
      ? isLoadingExplicit
      : canLoadForm && context === null && loadError === null;
    const badgeLabel = config.getBadgeLabel?.(isUpdateMode) ?? "Draft";
    const parentPid = config.getParentPid?.({ pid, context }) ?? (pid || null);
    const formKeySuffix =
      config.getFormKeySuffix?.({ id, pid }) ?? (id || pid || "standalone");
    const formComponentKind = child ? resolveFormComponentKind(child) : "accumulator";
    const FormComponent = config.formComponents[formComponentKind];

    async function handleSubmit(values: ChildFormValues) {
      if (!child || !context || !childFormIsReady(child, { pid, id })) {
        return;
      }

      setIsSaving(true);
      try {
        const markExpiredOptions =
          config.supportsMarkExpired && child === "mark_expired"
            ? { markAsExpiredId: markAsExpiredId || pid }
            : undefined;

        if (isUpdateMode && config.update && config.isEditableChildKind(child)) {
          await config.update(child, id, pid, values as Record<string, unknown>, context.formName, context);
          toast.success(`${title} updated`, {
            description: "The related transaction was saved successfully.",
          });
        } else {
          await config.create(
            child,
            pid,
            values as Record<string, unknown>,
            context.formName,
            { ...tempOptions, ...markExpiredOptions },
          );
          toast.success(`${title} created`, {
            description: "The related transaction was saved successfully.",
          });
        }
        router.push(listPath);
      } catch (error) {
        toast.error(
          error instanceof Error
            ? error.message
            : isUpdateMode
              ? "Related transaction could not be updated."
              : "Related transaction could not be saved.",
        );
        if (config.rethrowSubmitError) {
          throw error;
        }
      } finally {
        setIsSaving(false);
      }
    }

    if (!child || !childFormIsReady(child, { pid, id })) {
      const missingMessage =
        config.getMissingChildMessage?.({ child, loadError }) ??
        loadError ??
        "Missing child action.";

      return (
        <div className="flex min-h-full flex-col gap-4 px-4 py-8 lg:px-6">
          <p className="text-destructive text-sm">{missingMessage}</p>
          <Button variant="outline" size="sm" asChild>
            <Link href={listPath}>Back to list</Link>
          </Button>
        </div>
      );
    }

    return (
      <div className="flex min-h-full w-full min-w-0 flex-1 flex-col bg-muted/20">
        <div className="flex w-full min-w-0 flex-1 flex-col gap-6 px-4 pt-6 pb-24 lg:gap-8 lg:px-6 lg:pt-8">
          <header className="flex w-full min-w-0 flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
            <div className="flex min-w-0 items-start gap-4">
              <div className="flex size-11 shrink-0 items-center justify-center rounded-xl border border-primary/20 bg-primary/10 text-primary shadow-xs">
                <Layers3 className="size-5" />
              </div>
              <div className="min-w-0">
                <div className="flex flex-wrap items-center gap-2">
                  <h1 className="font-semibold text-2xl tracking-tight text-foreground">{pageHeading}</h1>
                  <Badge variant="outline" className="font-normal">
                    {badgeLabel}
                  </Badge>
                </div>
                {parentPid ? (
                  <p className="mt-1.5 text-muted-foreground text-sm leading-relaxed">
                    Parent {config.parentEntityLabel} #{parentPid}
                  </p>
                ) : null}
              </div>
            </div>
            <Button variant="outline" size="sm" className="shrink-0 gap-1.5" asChild>
              <Link href={listPath}>
                <ArrowLeft className="size-3.5" />
                Back to list
              </Link>
            </Button>
          </header>

          {isLoading ? (
            <p className="text-muted-foreground text-sm">Loading form…</p>
          ) : loadError ? (
            <p className="text-destructive text-sm">{loadError}</p>
          ) : (
            <FormComponent
              key={`${formComponentKind}-${formKeySuffix}`}
              formId={config.formId}
              initialValues={initialValues}
              fieldMeta={context?.fieldMeta}
              formOptionsRaw={context?.formOptions}
              onSubmit={handleSubmit}
            />
          )}
        </div>

        <div className="sticky bottom-0 z-20 border-t border-border/60 bg-background/90 shadow-[0_-4px_24px_-8px_rgba(0,0,0,0.08)] backdrop-blur-md dark:shadow-[0_-4px_24px_-8px_rgba(0,0,0,0.35)]">
          <div className="flex w-full flex-wrap items-center justify-between gap-3 px-4 py-3.5 lg:px-6">
            <p className="text-muted-foreground text-xs sm:text-sm">
              All required fields must be valid before saving
            </p>
            <div className="flex flex-wrap items-center gap-2">
              <Button variant="ghost" size="sm" className="text-muted-foreground" asChild>
                <Link href={listPath}>Cancel</Link>
              </Button>
              <Button
                type="submit"
                form={config.formId}
                size="sm"
                className="min-w-[7.5rem] px-6 shadow-sm"
                disabled={isLoading || Boolean(loadError) || isSaving}
              >
                {isSaving ? "Saving…" : isUpdateMode ? "Save changes" : "Create transaction"}
              </Button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return { ChildFormPage };
}
