"use client";

import { useCallback, useEffect, useState } from "react";
import { useForm, type FieldValues, type DefaultValues } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import {
  Plus,
  Pencil,
  Trash2,
  Download,
  RefreshCw,
  Printer,
  Copy,
  Eye,
} from "lucide-react";
import Link from "next/link";
import { z } from "zod";
import {
  Button,
  Dialog,
  Drawer,
  Input,
  EmptyState,
  FormField,
  ConfirmDialog,
  Select,
  Textarea,
  Badge,
} from "@/components/ds";
import {
  HospitalityTablePage,
  HospitalityStatGrid,
} from "@/modules/hospitality/design-system";
import {
  HospitalityPageLoader,
  HospitalityPageError,
  exportToCsv,
} from "@/modules/hospitality/pages/shared";
import { useTenantId } from "@/hooks/useTenantId";
import { useHospitalityCapabilities } from "@/modules/hospitality/hooks/useHospitalityCapabilities";
import { useHospitalityVenues } from "@/modules/hospitality/hooks/useHospitalityVenues";
import { HospitalityStatusChip } from "@/modules/hospitality/design-system";
import { HospitalityBundleGate } from "@/modules/hospitality/components/HospitalityBundleGate";
import { countByStatus } from "@/modules/hospitality/constants/fieldHelpers";

export type HospitalityFieldConfig = {
  name: string;
  label: string;
  type?: "text" | "number" | "email" | "tel" | "textarea" | "select" | "venue" | "datetime-local";
  options?: { value: string; label: string }[];
  required?: boolean;
  createOnly?: boolean;
  editOnly?: boolean;
  placeholder?: string;
};

export type HospitalityColumnConfig = {
  key: string;
  header: string;
  type?: "status" | "datetime" | "text" | "money";
  render?: (row: Record<string, unknown>) => React.ReactNode;
  searchable?: boolean;
  sortable?: boolean;
  defaultVisible?: boolean;
};

export type HospitalityRowAction = {
  label: string;
  onClick: (tenantId: string, row: Record<string, unknown>) => Promise<void>;
  variant?: "default" | "outline" | "danger";
};

type ApiResource = {
  list: (tenantId: string, params?: { page?: number; page_size?: number }) => Promise<Record<string, unknown>[]>;
  get?: (tenantId: string, id: string) => Promise<Record<string, unknown>>;
  create?: (tenantId: string, body: Record<string, unknown>) => Promise<unknown>;
  update?: (tenantId: string, id: string, body: Record<string, unknown>) => Promise<unknown>;
  remove?: (tenantId: string, id: string) => Promise<unknown>;
  upsert?: (tenantId: string, body: Record<string, unknown>) => Promise<unknown>;
};

export type HospitalityListConfig = {
  title: string;
  description?: string;
  breadcrumb?: string;
  resourceKey: string;
  bundleFeature?: string | null;
  permission?: string;
  api: ApiResource;
  columns: HospitalityColumnConfig[];
  createFields?: HospitalityFieldConfig[];
  editFields?: HospitalityFieldConfig[];
  filterDeleted?: boolean;
  listFilter?: (row: Record<string, unknown>) => boolean;
  rowActions?: HospitalityRowAction[];
  refreshIntervalMs?: number;
  statsKeys?: { total?: string; active?: string };
  quickActions?: { label: string; href: string }[];
  exportColumns?: string[];
  readOnly?: boolean;
  useUpsert?: boolean;
  emptyHint?: string;
  /** Honest API surface label for production UX */
  surfaceHint?: string;
};

function buildSchema(fields: HospitalityFieldConfig[]) {
  const shape: Record<string, z.ZodTypeAny> = {};
  for (const f of fields) {
    if (f.type === "number") {
      shape[f.name] = f.required ? z.coerce.number() : z.coerce.number().optional();
    } else {
      shape[f.name] = f.required
        ? z.string().min(1, `${f.label} الزامی است`)
        : z.string().optional();
    }
  }
  return z.object(shape);
}

function renderCell(col: HospitalityColumnConfig, row: Record<string, unknown>) {
  if (col.render) return col.render(row);
  const val = row[col.key];
  if (col.type === "status" && val) return <HospitalityStatusChip status={String(val)} />;
  if (col.type === "datetime" && val) {
    try {
      return new Date(String(val)).toLocaleString("fa-IR");
    } catch {
      return String(val);
    }
  }
  if (col.type === "money" && val != null) {
    return `${Number(val).toLocaleString("fa-IR")} ${row.currency_code ?? "IRR"}`;
  }
  return val != null ? String(val) : "—";
}

function renderField(
  field: HospitalityFieldConfig,
  register: ReturnType<typeof useForm>["register"],
  mode: "create" | "edit",
  venues: Record<string, unknown>[]
) {
  if (mode === "create" && field.editOnly) return null;
  if (mode === "edit" && field.createOnly) return null;

  if (field.type === "textarea") {
    return (
      <FormField key={field.name} label={field.label}>
        <Textarea {...register(field.name)} rows={3} placeholder={field.placeholder} />
      </FormField>
    );
  }
  if (field.type === "select" && field.options) {
    return (
      <FormField key={field.name} label={field.label}>
        <Select {...register(field.name)}>
          <option value="">انتخاب…</option>
          {field.options.map((o) => (
            <option key={o.value} value={o.value}>
              {o.label}
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  if (field.type === "venue") {
    return (
      <FormField key={field.name} label={field.label}>
        <Select {...register(field.name)}>
          <option value="">انتخاب مکان…</option>
          {venues.map((v) => (
            <option key={String(v.id)} value={String(v.id)}>
              {String(v.name)} ({String(v.code)})
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  return (
    <FormField key={field.name} label={field.label}>
      <Input
        type={field.type === "datetime-local" ? "datetime-local" : field.type ?? "text"}
        {...register(field.name)}
        placeholder={field.placeholder}
      />
    </FormField>
  );
}

function filterStorageKey(resourceKey: string) {
  return `hospitality-saved-filter-${resourceKey}`;
}

export function createHospitalityListPage(config: HospitalityListConfig) {
  return function HospitalityListPage() {
    const { tenantId } = useTenantId();
    const qc = useQueryClient();
    const caps = useHospitalityCapabilities();
    const venuesQ = useHospitalityVenues();
    const [createOpen, setCreateOpen] = useState(false);
    const [editRow, setEditRow] = useState<Record<string, unknown> | null>(null);
    const [detailRow, setDetailRow] = useState<Record<string, unknown> | null>(null);
    const [deleteId, setDeleteId] = useState<string | null>(null);
    const [page, setPage] = useState(1);
    const [selected, setSelected] = useState<Set<string>>(new Set());
    const [statusFilter, setStatusFilter] = useState("");
    const [showDeleted, setShowDeleted] = useState(false);
    const pageSize = 20;

    const createFields = config.createFields ?? [];
    const editFields = config.editFields ?? createFields;
    const createSchema = buildSchema(createFields);
    const editSchema = buildSchema(editFields);

    useEffect(() => {
      if (typeof window === "undefined") return;
      const saved = localStorage.getItem(filterStorageKey(config.resourceKey));
      if (saved) setStatusFilter(saved);
    }, [config.resourceKey]);

    const saveFilter = useCallback(
      (value: string) => {
        setStatusFilter(value);
        if (typeof window !== "undefined") {
          localStorage.setItem(filterStorageKey(config.resourceKey), value);
        }
      },
      [config.resourceKey]
    );

    const listQ = useQuery({
      queryKey: ["hospitality", tenantId, config.resourceKey, page],
      queryFn: () => config.api.list(tenantId!, { page, page_size: 500 }),
      enabled: !!tenantId,
      refetchInterval: config.refreshIntervalMs,
    });

    const createForm = useForm({
      resolver: zodResolver(createSchema),
      defaultValues: Object.fromEntries(createFields.map((f) => [f.name, ""])) as DefaultValues<FieldValues>,
    });
    const editForm = useForm({ resolver: zodResolver(editSchema) });

    const invalidate = () =>
      qc.invalidateQueries({ queryKey: ["hospitality", tenantId, config.resourceKey] });

    const createM = useMutation({
      mutationFn: (d: FieldValues) => {
        const body = { ...d };
        if (config.useUpsert && config.api.upsert) return config.api.upsert(tenantId!, body);
        return config.api.create!(tenantId!, body);
      },
      onSuccess: async () => {
        toast.success(config.useUpsert ? "تنظیمات ذخیره شد" : "رکورد ایجاد شد");
        setCreateOpen(false);
        createForm.reset();
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    const updateM = useMutation({
      mutationFn: (d: FieldValues) => config.api.update!(tenantId!, String(editRow!.id), d),
      onSuccess: async () => {
        toast.success("به‌روزرسانی شد");
        setEditRow(null);
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    const deleteM = useMutation({
      mutationFn: (id: string) => config.api.remove!(tenantId!, id),
      onSuccess: async () => {
        toast.success("حذف شد");
        setDeleteId(null);
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    useEffect(() => {
      const handler = (e: KeyboardEvent) => {
        if ((e.ctrlKey || e.metaKey) && e.key === "n" && config.api.create && !config.readOnly) {
          e.preventDefault();
          setCreateOpen(true);
        }
        if ((e.ctrlKey || e.metaKey) && e.key === "r") {
          e.preventDefault();
          listQ.refetch();
        }
      };
      window.addEventListener("keydown", handler);
      return () => window.removeEventListener("keydown", handler);
    }, [config.api.create, config.readOnly, listQ]);

    if (!tenantId || listQ.isLoading || caps.isLoading) return <HospitalityPageLoader />;
    if (listQ.error) return <HospitalityPageError error={listQ.error} onRetry={() => listQ.refetch()} />;

    let rows = listQ.data ?? [];
    if (config.listFilter) rows = rows.filter(config.listFilter);
    if (config.filterDeleted && !showDeleted) rows = rows.filter((r) => !r.is_deleted);
    if (statusFilter) rows = rows.filter((r) => String(r.status ?? "") === statusFilter);

    const stats = countByStatus(rows);
    const venues = venuesQ.data ?? [];
    const exportCols =
      config.exportColumns ?? config.columns.map((c) => c.key).filter((k) => k !== "actions");

    const duplicateRow = (row: Record<string, unknown>) => {
      createForm.reset(
        Object.fromEntries(
          createFields.map((f) => [f.name, row[f.name] != null ? String(row[f.name]) : ""])
        )
      );
      setCreateOpen(true);
    };

    const tableColumns = [
      ...config.columns.map((c) => ({
        key: c.key,
        header: c.header,
        searchable: c.searchable,
        sortable: c.sortable,
        defaultVisible: c.defaultVisible,
        render: (row: Record<string, unknown>) => renderCell(c, row),
      })),
      {
        key: "actions",
        header: "عملیات",
        searchable: false as const,
        sortable: false as const,
        render: (row: Record<string, unknown>) => (
          <div className="flex flex-wrap gap-1">
            <Button variant="ghost" size="icon" aria-label="جزئیات" onClick={() => setDetailRow(row)}>
              <Eye className="h-4 w-4" />
            </Button>
            {config.api.create && !config.readOnly ? (
              <Button variant="ghost" size="icon" aria-label="کپی" onClick={() => duplicateRow(row)}>
                <Copy className="h-4 w-4" />
              </Button>
            ) : null}
            {config.api.update && !config.readOnly ? (
              <Button
                variant="ghost"
                size="icon"
                aria-label="ویرایش"
                onClick={() => {
                  setEditRow(row);
                  editForm.reset(
                    Object.fromEntries(editFields.map((f) => [f.name, row[f.name] ?? ""]))
                  );
                }}
              >
                <Pencil className="h-4 w-4" />
              </Button>
            ) : null}
            {config.api.remove && !row.is_deleted && !config.readOnly ? (
              <Button variant="ghost" size="icon" aria-label="حذف" onClick={() => setDeleteId(String(row.id))}>
                <Trash2 className="h-4 w-4" />
              </Button>
            ) : null}
            {row.is_deleted ? (
              <Badge tone="warning">حذف‌شده</Badge>
            ) : null}
            {config.rowActions?.map((action) => (
              <Button
                key={action.label}
                variant={action.variant ?? "outline"}
                size="sm"
                onClick={async () => {
                  try {
                    await action.onClick(tenantId!, row);
                    toast.success(action.label);
                    await invalidate();
                  } catch (e) {
                    toast.error(e instanceof Error ? e.message : "خطا");
                  }
                }}
              >
                {action.label}
              </Button>
            ))}
          </div>
        ),
      },
    ];

    const body = (
      <>
        {(() => {
          const hasUpdate = Boolean(config.api.update) && !config.readOnly;
          const hasRemove = Boolean(config.api.remove) && !config.readOnly;
          const hasCreate =
            Boolean(config.api.create || config.api.upsert) && !config.readOnly;
          const hint =
            config.surfaceHint ||
            (config.readOnly
              ? "نمای زنده از API — ویرایش از این صفحه انجام نمی‌شود."
              : hasCreate && !hasUpdate && !hasRemove
                ? "سطح API فعلی: ایجاد + فهرست + جزئیات. ویرایش/حذف در قرارداد منتشرشده backend موجود نیست."
                : hasCreate && hasUpdate
                  ? "CRUD کامل از API زنده."
                  : null);
          if (!hint) return null;
          return (
            <div
              className="mb-4 rounded-xl border border-[var(--border)] bg-[var(--surface-muted)] px-3 py-2 text-xs text-[var(--muted)]"
              role="status"
            >
              {hint}
            </div>
          );
        })()}
        <HospitalityStatGrid
          stats={[
            { label: "کل رکوردها", value: stats.total, hint: config.title },
            { label: "فعال", value: stats.active },
            { label: "پیش‌نویس", value: stats.draft },
            {
              label: "صفحه",
              value: page,
              hint: `${Math.ceil(rows.length / pageSize) || 1} صفحه`,
            },
          ]}
        />
        {config.quickActions?.length ? (
          <div className="mb-4 flex flex-wrap gap-2">
            {config.quickActions.map((a) => (
              <Link key={a.href} href={a.href}>
                <Button variant="outline" size="sm">
                  {a.label}
                </Button>
              </Link>
            ))}
          </div>
        ) : null}
        <HospitalityTablePage
          title={config.title}
          description={config.description}
          breadcrumb={config.breadcrumb ?? config.title}
          columns={tableColumns}
          rows={rows}
          page={page}
          pageSize={pageSize}
          onPageChange={setPage}
          selectedIds={config.api.remove && !config.readOnly ? selected : undefined}
          onSelectionChange={config.api.remove && !config.readOnly ? setSelected : undefined}
          bulkActions={
            config.api.remove && selected.size > 0 ? (
              <Button
                variant="outline"
                size="sm"
                onClick={async () => {
                  for (const id of selected) {
                    await config.api.remove!(tenantId!, id);
                  }
                  toast.success("حذف گروهی انجام شد");
                  setSelected(new Set());
                  await invalidate();
                }}
              >
                حذف انتخاب‌شده‌ها
              </Button>
            ) : undefined
          }
          actions={
            <div className="flex flex-wrap gap-2">
              {!config.readOnly && (config.api.create || config.api.upsert) && createFields.length > 0 ? (
                <Button onClick={() => setCreateOpen(true)}>
                  <Plus className="h-4 w-4" />
                  {config.useUpsert ? "افزودن/ویرایش" : "جدید"}
                </Button>
              ) : null}
            </div>
          }
          toolbar={
            <div className="flex flex-wrap items-center gap-2">
              <select
                className="rounded-lg border border-[var(--border)] bg-[var(--surface)] px-3 py-2 text-sm"
                value={statusFilter}
                onChange={(e) => saveFilter(e.target.value)}
                aria-label="فیلتر وضعیت"
              >
                <option value="">همه وضعیت‌ها</option>
                <option value="draft">پیش‌نویس</option>
                <option value="active">فعال</option>
                <option value="inactive">غیرفعال</option>
                <option value="published">منتشر شده</option>
                <option value="open">باز</option>
                <option value="completed">تکمیل</option>
              </select>
              {config.filterDeleted ? (
                <label className="flex items-center gap-2 text-sm">
                  <input
                    type="checkbox"
                    checked={showDeleted}
                    onChange={(e) => setShowDeleted(e.target.checked)}
                  />
                  نمایش حذف‌شده‌ها
                </label>
              ) : null}
              <Button variant="outline" size="sm" onClick={() => listQ.refetch()} aria-label="بروزرسانی">
                <RefreshCw className="h-4 w-4" />
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={() => exportToCsv(config.title, rows, exportCols)}
              >
                <Download className="h-4 w-4" />
                CSV
              </Button>
              <Button variant="outline" size="sm" onClick={() => window.print()}>
                <Printer className="h-4 w-4" />
              </Button>
            </div>
          }
          empty={
            <EmptyState
              title="موردی یافت نشد"
              description={
                config.emptyHint ||
                (config.readOnly
                  ? "داده‌ای از API برنگشته است. فیلتر را پاک کنید یا بعداً دوباره تلاش کنید."
                  : "هنوز رکوردی نیست — اولین مورد را از دکمه ایجاد بسازید.")
              }
              action={
                config.api.create && !config.readOnly ? (
                  <Button onClick={() => setCreateOpen(true)}>ایجاد اولین رکورد</Button>
                ) : undefined
              }
            />
          }
        />
      </>
    );

    const pageContent = config.bundleFeature ? (
      <HospitalityBundleGate feature={config.bundleFeature} capabilities={caps.data}>
        {body}
      </HospitalityBundleGate>
    ) : (
      body
    );

    return (
      <>
        {pageContent}
        {!config.readOnly && (config.api.create || config.api.upsert) && createFields.length > 0 ? (
          <Dialog
            open={createOpen}
            onClose={() => setCreateOpen(false)}
            title={`${config.title} — ${config.useUpsert ? "ذخیره" : "جدید"}`}
          >
            <form className="space-y-3" onSubmit={createForm.handleSubmit((d) => createM.mutate(d))}>
              {createFields.map((f) => renderField(f, createForm.register, "create", venues))}
              <div className="flex justify-end gap-2">
                <Button type="button" variant="outline" onClick={() => setCreateOpen(false)}>
                  انصراف
                </Button>
                <Button type="submit" disabled={createM.isPending}>
                  ذخیره
                </Button>
              </div>
            </form>
          </Dialog>
        ) : null}
        {editRow && config.api.update && !config.readOnly ? (
          <Drawer open={!!editRow} onClose={() => setEditRow(null)} title={`${config.title} — ویرایش`}>
            <form className="space-y-3" onSubmit={editForm.handleSubmit((d) => updateM.mutate(d))}>
              {editFields.map((f) => renderField(f, editForm.register, "edit", venues))}
              <div className="flex justify-end gap-2">
                <Button type="button" variant="outline" onClick={() => setEditRow(null)}>
                  انصراف
                </Button>
                <Button type="submit" disabled={updateM.isPending}>
                  به‌روزرسانی
                </Button>
              </div>
            </form>
          </Drawer>
        ) : null}
        {detailRow ? (
          <Drawer open={!!detailRow} onClose={() => setDetailRow(null)} title="جزئیات رکورد">
            <div className="space-y-3 text-sm">
              {config.columns.map((c) => (
                <div key={c.key} className="flex justify-between gap-4 border-b border-[var(--border)] pb-2">
                  <span className="text-[var(--muted)]">{c.header}</span>
                  <span className="font-medium">{renderCell(c, detailRow)}</span>
                </div>
              ))}
              <div className="mt-4 rounded-xl bg-[var(--surface-muted)] p-3 text-xs text-[var(--muted)]">
                <p>ایجاد: {detailRow.created_at ? new Date(String(detailRow.created_at)).toLocaleString("fa-IR") : "—"}</p>
                <p>به‌روزرسانی: {detailRow.updated_at ? new Date(String(detailRow.updated_at)).toLocaleString("fa-IR") : "—"}</p>
                <p>ایجادکننده: {String(detailRow.created_by ?? "—")}</p>
              </div>
            </div>
          </Drawer>
        ) : null}
        <ConfirmDialog
          open={!!deleteId}
          onClose={() => setDeleteId(null)}
          onConfirm={() => deleteId && deleteM.mutate(deleteId)}
          title="حذف رکورد"
          description="آیا از حذف این رکورد مطمئن هستید؟"
          confirmLabel="حذف"
          danger
        />
      </>
    );
  };
}
