"use client";

import type { ComponentType, ReactNode } from "react";
import { Upload } from "lucide-react";
import { toast } from "sonner";

import { DataTableHeaderActions } from "@/app/dashboard/_components/data-table";
import { Button } from "@/components/ui/button";

type RefreshProps = {
  isRefreshing?: boolean;
  onRefresh?: () => void;
};

type UploadOptions = {
  uploadToastMessage: string;
  uploadLabel?: string;
  uploadPlacement?: "middle" | "suffix";
};

type Slot<TProps> = ReactNode | ((props: TProps) => ReactNode);

export type MasterHeaderActionsProps<
  TRow = void,
  TExtra = object,
> = RefreshProps &
  TExtra &
  (TRow extends void ? object : { data: TRow[] });

export type MasterHeaderActionsConfig<
  TRow = void,
  TExtra = object,
> = {
  createHref?: string | ((props: MasterHeaderActionsProps<TRow, TExtra>) => string);
  createLabel?: string;
  exportFilename?: string;
  onExport?: (data: TRow[]) => void;
  exportRows?: (data: TRow[]) => void;
  exportLabel?: string;
  prefixActions?: Slot<MasterHeaderActionsProps<TRow, TExtra>>;
  middleActions?: Slot<MasterHeaderActionsProps<TRow, TExtra>>;
  suffixActions?: Slot<MasterHeaderActionsProps<TRow, TExtra>>;
} & Partial<UploadOptions>;

function resolveSlot<TProps>(slot: Slot<TProps> | undefined, props: TProps): ReactNode {
  if (slot === undefined) return undefined;
  return typeof slot === "function" ? slot(props) : slot;
}

function combineActions(...parts: (ReactNode | false | null | undefined)[]): ReactNode | undefined {
  const filtered = parts.filter((part) => part != null && part !== false);
  if (filtered.length === 0) return undefined;
  if (filtered.length === 1) return filtered[0];
  return <>{filtered}</>;
}

function createUploadButton(message: string, label = "Upload"): ReactNode {
  return (
    <Button
      variant="outline"
      size="sm"
      className="gap-1.5"
      onClick={() => toast.info(message)}
    >
      <Upload className="size-4" />
      {label}
    </Button>
  );
}

export function createMasterHeaderActions<
  TRow = void,
  TExtra = object,
>(
  config: MasterHeaderActionsConfig<TRow, TExtra>,
): ComponentType<MasterHeaderActionsProps<TRow, TExtra>> {
  function MasterHeaderActions(props: MasterHeaderActionsProps<TRow, TExtra>) {
    const createHref =
      typeof config.createHref === "function" ? config.createHref(props) : config.createHref;

    const exportHandler = config.onExport ?? config.exportRows;
    const onExport =
      exportHandler && "data" in props
        ? () => exportHandler((props as { data: TRow[] }).data)
        : exportHandler
          ? () => exportHandler([] as TRow[])
          : undefined;

    const uploadButton =
      config.uploadToastMessage !== undefined
        ? createUploadButton(config.uploadToastMessage, config.uploadLabel)
        : null;
    const uploadPlacement = config.uploadPlacement ?? "suffix";

    return (
      <DataTableHeaderActions
        createHref={createHref}
        createLabel={config.createLabel}
        onExport={onExport}
        exportLabel={config.exportLabel}
        isRefreshing={props.isRefreshing}
        onRefresh={props.onRefresh}
        prefixActions={resolveSlot(config.prefixActions, props)}
        middleActions={combineActions(
          resolveSlot(config.middleActions, props),
          uploadPlacement === "middle" ? uploadButton : null,
        )}
        suffixActions={combineActions(
          resolveSlot(config.suffixActions, props),
          uploadPlacement === "suffix" ? uploadButton : null,
        )}
      />
    );
  }

  return MasterHeaderActions;
}
