"use client";

import { useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Eye, Pencil, Plus, Trash2, X } from "lucide-react";
import { accountingApi } from "@/src/modules/accounting/services/accounting-api";
import { useTenantId } from "@/hooks/useTenantId";
import { formatMoney, parseMoneyInput } from "@/lib/utils";
import {
  PageHeader,
  Button,
  Input,
  DataTable,
  EmptyState,
  LoadingState,
  ErrorState,
  Badge,
  FormField,
  MoneyInput,
  DatePicker,
  JalaliDateText,
  ConfirmDialog,
  Select,
} from "@/src/shared/ui";
import { ItemCombobox, PartyCombobox } from "@/src/modules/accounting/components/EntityCombobox";

export type DocKind =
  | "invoice"
  | "order"
  | "request"
  | "receipt"
  | "transfer"
  | "adjustment"
  | "settlement"
  | "generic";

type LineValues = { title: string; qty: string; unit_price: string; note?: string; item_id?: string };

const formSchema = z.object({
  number: z.string().optional(),
  doc_date: z.string().min(1, "تاریخ الزامی است"),
  party_name: z.string().optional(),
  party_id: z.string().optional(),
  description: z.string().optional(),
  amount: z.string().optional(),
  warehouse_id: z.string().optional(),
  warehouse_name: z.string().optional(),
  credit_mode: z.string().optional(),
  source_note: z.string().optional(),
  movement_type: z.string().optional(),
  lines: z
    .array(
      z.object({
        title: z.string().min(1, "شرح ردیف الزامی است"),
        qty: z.string().min(1, "تعداد الزامی است"),
        unit_price: z.string().min(1, "فی الزامی است"),
        note: z.string().optional(),
        item_id: z.string().optional(),
      })
    )
    .optional(),
});

type FormValues = z.infer<typeof formSchema>;

function PortalDialog({
  open,
  onClose,
  title,
  children,
  wide,
}: {
  open: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
  wide?: boolean;
}) {
  if (!open || typeof document === "undefined") return null;
  return createPortal(
    <div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
      <button type="button" aria-label="بستن" className="absolute inset-0 bg-black/45" onClick={onClose} />
      <div
        role="dialog"
        aria-modal="true"
        className={`relative z-10 max-h-[92vh] w-full overflow-y-auto rounded-2xl border border-[var(--border)] bg-[var(--surface)] shadow-[var(--shadow-lg)] ${
          wide ? "max-w-4xl" : "max-w-2xl"
        }`}
      >
        <div className="sticky top-0 z-10 flex items-start justify-between gap-3 border-b border-[var(--border)] bg-[var(--surface)] px-5 py-4">
          <h2 className="text-base font-semibold text-secondary">{title}</h2>
          <Button type="button" variant="ghost" size="icon" onClick={onClose} aria-label="بستن">
            <X className="h-4 w-4" />
          </Button>
        </div>
        <div className="px-5 py-4">{children}</div>
      </div>
    </div>,
    document.body
  );
}

function sumLines(lines: LineValues[] | undefined): string {
  if (!lines?.length) return "0";
  const total = lines.reduce((acc, line) => {
    const qty = Number(parseMoneyInput(line.qty) || "0");
    const price = Number(parseMoneyInput(line.unit_price) || "0");
    return acc + qty * price;
  }, 0);
  return String(total);
}

function parseMeta(meta: unknown): {
  lines?: LineValues[];
  warehouse_id?: string;
  warehouse_name?: string;
  credit_mode?: string;
  source_note?: string;
  movement_type?: string;
} {
  if (!meta) return {};
  if (typeof meta === "string") {
    try {
      return JSON.parse(meta) as {
        lines?: LineValues[];
        warehouse_id?: string;
        warehouse_name?: string;
        credit_mode?: string;
        source_note?: string;
      };
    } catch {
      return {};
    }
  }
  if (typeof meta === "object") {
    return meta as {
      lines?: LineValues[];
      warehouse_id?: string;
      warehouse_name?: string;
      credit_mode?: string;
      source_note?: string;
    };
  }
  return {};
}

/**
 * Full operational document screen for sales / purchase / inventory submenus.
 * Real CRUD via /api/v1/ops/documents — no mocks.
 */
export function OperationalDocumentPage({
  title,
  description,
  module,
  docType,
  createLabel,
  partyLabel = "طرف حساب",
  kind = "generic",
  enableAccountingPost,
  enableWarehouseContext = false,
}: {
  title: string;
  description?: string;
  module: string;
  docType: string;
  createLabel: string;
  partyLabel?: string;
  kind?: DocKind;
  /** When set, draft rows get "ثبت حسابداری" using the matching engine. */
  enableAccountingPost?: "sales" | "purchase_gr" | "purchase_invoice" | "purchase_return";
  /** Show warehouse select separately from party (طرف حساب). */
  enableWarehouseContext?: boolean;
}) {
  const { tenantId } = useTenantId();
  const qc = useQueryClient();
  const withLines = kind === "invoice" || kind === "order" || kind === "receipt" || kind === "request";
  const showPurchaseCreditMode = enableAccountingPost === "purchase_gr";
  const showMovementType = module === "inventory";

  const [createOpen, setCreateOpen] = useState(false);
  const [detailRow, setDetailRow] = useState<Record<string, unknown> | null>(null);
  const [editRow, setEditRow] = useState<Record<string, unknown> | null>(null);
  const [confirmId, setConfirmId] = useState<string | null>(null);
  const [postRow, setPostRow] = useState<Record<string, unknown> | null>(null);
  const [preview, setPreview] = useState<{ is_balanced: boolean; total_debit: string; total_credit?: string } | null>(
    null
  );

  const listQ = useQuery({
    queryKey: ["accounting", tenantId, "ops-docs", module, docType],
    queryFn: () => accountingApi.ops.listDocuments(tenantId!, module, docType),
    enabled: !!tenantId,
  });
  const salesProfilesQ = useQuery({
    queryKey: ["accounting", tenantId, "sales-profiles"],
    queryFn: () => accountingApi.salesAccounting.listProfiles(tenantId!),
    enabled: !!tenantId && enableAccountingPost === "sales",
  });
  const purchaseProfilesQ = useQuery({
    queryKey: ["accounting", tenantId, "purchase-profiles"],
    queryFn: async () => {
      const rows = await accountingApi.purchaseInventory.listProfiles(tenantId!);
      if (rows.some((p) => p.is_default && p.is_active)) return rows;
      await accountingApi.purchaseInventory.ensureDefaultProfile(tenantId!).catch(() => null);
      return accountingApi.purchaseInventory.listProfiles(tenantId!);
    },
    enabled:
      !!tenantId &&
      (enableAccountingPost === "purchase_gr" ||
        enableAccountingPost === "purchase_invoice" ||
        enableAccountingPost === "purchase_return"),
  });
  const policyQ = useQuery({
    queryKey: ["accounting", tenantId, "posting-policy"],
    queryFn: () => accountingApi.setup.getPostingPolicy(tenantId!),
    enabled: !!tenantId,
  });
  const warehousesQ = useQuery({
    queryKey: ["accounting", tenantId, "warehouses"],
    queryFn: () => accountingApi.ops.listWarehouses(tenantId!),
    enabled: !!tenantId && enableWarehouseContext,
  });

  const defaults: FormValues = useMemo(
    () => ({
      number: "",
      doc_date: new Date().toISOString().slice(0, 10),
      party_name: "",
      party_id: "",
      description: "",
      amount: "0",
      warehouse_id: "",
      warehouse_name: "",
      credit_mode: "supplier",
      source_note: "",
      movement_type: "in",
      // Always an array so useFieldArray stays stable (even when lines UI is hidden).
      lines: withLines ? [{ title: "", qty: "1", unit_price: "0", note: "", item_id: "" }] : [],
    }),
    [withLines]
  );

  const form = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: defaults,
  });
  const editForm = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: defaults,
  });
  const postForm = useForm({
    defaultValues: { profile_id: "", discount_amount: "0", tax_amount: "0" },
  });

  const createLines = useFieldArray({ control: form.control, name: "lines" });
  const editLines = useFieldArray({ control: editForm.control, name: "lines" });

  const watchedCreateLines = form.watch("lines");
  const createTotal = withLines ? sumLines(watchedCreateLines) : form.watch("amount") || "0";

  const invalidate = async () => {
    await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "ops-docs", module, docType] });
  };

  const createM = useMutation({
    mutationFn: (d: FormValues) => {
      const amount = withLines ? sumLines(d.lines) : parseMoneyInput(d.amount || "0") || "0";
      const meta: Record<string, unknown> = {};
      if (withLines) meta.lines = d.lines ?? [];
      if (enableWarehouseContext) {
        meta.warehouse_id = d.warehouse_id || undefined;
        meta.warehouse_name = d.warehouse_name || undefined;
        meta.source_note = d.source_note || undefined;
        if (showPurchaseCreditMode) {
          meta.credit_mode = d.credit_mode || "supplier";
        }
        if (showMovementType) {
          meta.movement_type = d.movement_type || "in";
        }
      }
      return accountingApi.ops.createDocument(tenantId!, {
        module,
        doc_type: docType,
        number: d.number?.trim() || undefined,
        doc_date: d.doc_date,
        party_name: d.party_name || undefined,
        party_id: d.party_id || undefined,
        amount,
        description: d.description || undefined,
        status: "draft",
        meta_json: Object.keys(meta).length ? JSON.stringify(meta) : undefined,
      });
    },
    onSuccess: async () => {
      toast.success(`${title} ثبت شد`);
      setCreateOpen(false);
      form.reset(defaults);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const updateM = useMutation({
    mutationFn: (d: FormValues) => {
      const amount = withLines ? sumLines(d.lines) : parseMoneyInput(d.amount || "0") || "0";
      const meta: Record<string, unknown> = {};
      if (withLines) meta.lines = d.lines ?? [];
      if (enableWarehouseContext) {
        meta.warehouse_id = d.warehouse_id || undefined;
        meta.warehouse_name = d.warehouse_name || undefined;
        meta.source_note = d.source_note || undefined;
        if (showPurchaseCreditMode) {
          meta.credit_mode = d.credit_mode || "supplier";
        }
        if (showMovementType) {
          meta.movement_type = d.movement_type || "in";
        }
      }
      return accountingApi.ops.updateDocument(tenantId!, String(editRow!.id), {
        doc_date: d.doc_date,
        party_name: d.party_name || undefined,
        party_id: d.party_id || undefined,
        amount,
        description: d.description || undefined,
        meta_json: Object.keys(meta).length ? JSON.stringify(meta) : undefined,
      });
    },
    onSuccess: async () => {
      toast.success("ویرایش ذخیره شد");
      setEditRow(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const confirmM = useMutation({
    mutationFn: (id: string) => accountingApi.ops.confirmDocument(tenantId!, id),
    onSuccess: async (doc) => {
      const meta =
        doc && typeof doc === "object" && "meta_json" in doc && typeof doc.meta_json === "string"
          ? (() => {
              try {
                return JSON.parse(doc.meta_json as string) as {
                  accounting_voucher?: { voucher_number?: string };
                };
              } catch {
                return null;
              }
            })()
          : null;
      const vn = meta?.accounting_voucher?.voucher_number;
      toast.success(vn ? `تأیید شد و سند حسابداری ${vn} صادر شد` : "تأیید شد");
      setConfirmId(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const previewM = useMutation({
    mutationFn: async () => {
      if (!postRow) throw new Error("سندی انتخاب نشده");
      const amount = String(postRow.amount ?? "0");
      const profileId = postForm.getValues("profile_id") || undefined;
      if (enableAccountingPost === "sales") {
        return accountingApi.salesAccounting.preview(tenantId!, {
          document_type: docType === "return" ? "return" : "invoice",
          total_amount: amount,
          discount_amount: postForm.getValues("discount_amount") || "0",
          tax_amount: postForm.getValues("tax_amount") || "0",
          profile_id: profileId,
        });
      }
      if (enableAccountingPost === "purchase_invoice" || enableAccountingPost === "purchase_return") {
        return accountingApi.purchaseInventory.previewPurchaseInvoice(tenantId!, {
          source_document_id: String(postRow.id),
          amount,
          profile_id: profileId,
        });
      }
      return accountingApi.purchaseInventory.previewGoodsReceipt(tenantId!, {
        source_document_id: String(postRow.id),
        amount,
        profile_id: profileId,
      });
    },
    onSuccess: (data) => {
      setPreview(data);
      toast.success("پیش‌نمایش آماده شد");
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const postM = useMutation({
    mutationFn: async () => {
      if (!postRow) throw new Error("سندی انتخاب نشده");
      const amount = String(postRow.amount ?? "0");
      const profileId = postForm.getValues("profile_id") || undefined;
      if (enableAccountingPost === "sales") {
        return accountingApi.salesAccounting.post(tenantId!, {
          document_type: docType === "return" ? "return" : "invoice",
          source_document_id: String(postRow.id),
          total_amount: amount,
          discount_amount: postForm.getValues("discount_amount") || "0",
          tax_amount: postForm.getValues("tax_amount") || "0",
          profile_id: profileId,
        });
      }
      if (enableAccountingPost === "purchase_return") {
        return accountingApi.purchaseInventory.postPurchaseReturn(tenantId!, {
          source_document_id: String(postRow.id),
          amount,
          profile_id: profileId,
        });
      }
      if (enableAccountingPost === "purchase_invoice") {
        return accountingApi.purchaseInventory.postPurchaseInvoice(tenantId!, {
          source_document_id: String(postRow.id),
          amount,
          profile_id: profileId,
        });
      }
      return accountingApi.purchaseInventory.postGoodsReceipt(tenantId!, {
        source_document_id: String(postRow.id),
        amount,
        profile_id: profileId,
        credit_mode: parseMeta(postRow.meta_json).credit_mode || "supplier",
        warehouse_name: parseMeta(postRow.meta_json).warehouse_name || undefined,
        source_note: parseMeta(postRow.meta_json).source_note || undefined,
        party_name: postRow.party_name ? String(postRow.party_name) : undefined,
      });
    },
    onSuccess: async (data) => {
      const voucher =
        data && typeof data === "object" && "voucher_number" in data
          ? String((data as { voucher_number?: string }).voucher_number || "")
          : "";
      toast.success(voucher ? `سند حسابداری ${voucher} صادر شد` : "ثبت حسابداری انجام شد");
      setPostRow(null);
      setPreview(null);
      if (postRow?.status === "draft") {
        await accountingApi.ops.confirmDocument(tenantId!, String(postRow.id)).catch(() => null);
      }
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const openCreate = async () => {
    form.reset(defaults);
    setCreateOpen(true);
    try {
      const seq = await accountingApi.setup.peekNumber(tenantId!, `ops.${module}.${docType}`);
      form.setValue("number", seq.preview);
    } catch {
      // BE still allocates if blank on submit
    }
  };

  const openEdit = (row: Record<string, unknown>) => {
    const meta = parseMeta(row.meta_json);
    editForm.reset({
      number: String(row.number ?? ""),
      doc_date: String(row.doc_date ?? ""),
      party_name: String(row.party_name ?? ""),
      party_id: String(row.party_id ?? ""),
      description: String(row.description ?? ""),
      amount: String(row.amount ?? "0"),
      warehouse_id: meta.warehouse_id ?? "",
      warehouse_name: meta.warehouse_name ?? "",
      credit_mode: meta.credit_mode ?? "supplier",
      source_note: meta.source_note ?? "",
      movement_type: meta.movement_type ?? "in",
      lines: withLines
        ? meta.lines?.length
          ? meta.lines
          : [{ title: "", qty: "1", unit_price: String(row.amount ?? "0"), note: "", item_id: "" }]
        : [],
    });
    setEditRow(row);
  };

  if (!tenantId || listQ.isLoading) return <LoadingState />;
  if (listQ.error) {
    return <ErrorState message={listQ.error.message} onRetry={() => listQ.refetch()} />;
  }

  const rows = (listQ.data ?? []) as unknown as Record<string, unknown>[];
  const profiles =
    enableAccountingPost === "sales" ? salesProfilesQ.data ?? [] : purchaseProfilesQ.data ?? [];

  const renderDocForm = (
    f: typeof form,
    linesArray: typeof createLines,
    onSubmit: (d: FormValues) => void,
    pending: boolean,
    onCancel: () => void,
    totalHint: string,
    numberReadOnly?: boolean
  ) => (
    <form className="grid gap-3 sm:grid-cols-2" onSubmit={f.handleSubmit(onSubmit)}>
      <FormField
        label="شماره سند"
        error={f.formState.errors.number?.message}
      >
        <Input
          {...f.register("number")}
          readOnly={numberReadOnly}
          placeholder="خودکار از سیستم"
        />
      </FormField>
      <FormField label="تاریخ" error={f.formState.errors.doc_date?.message}>
        <Controller
          control={f.control}
          name="doc_date"
          render={({ field }) => (
            <DatePicker value={field.value} onChange={field.onChange} onBlur={field.onBlur} name={field.name} />
          )}
        />
      </FormField>
      <FormField label={partyLabel} hint="شخص یا شرکت طرف معامله (جدا از انبار)">
        <PartyCombobox
          module={module}
          valueName={f.watch("party_name") || undefined}
          placeholder={`جستجوی ${partyLabel}…`}
          onChange={(party) => {
            f.setValue("party_name", party?.name || "", { shouldDirty: true });
            f.setValue("party_id", party?.id || "", { shouldDirty: true });
          }}
        />
      </FormField>
      {enableWarehouseContext ? (
        <>
          {showMovementType ? (
            <FormField label="نوع رسید" hint="ورود به انبار یا خروج از انبار">
              <Select {...f.register("movement_type")}>
                <option value="in">ورود به انبار</option>
                <option value="out">خروج از انبار</option>
              </Select>
            </FormField>
          ) : null}
          <FormField
            label={showMovementType ? "انبار" : "انبار مقصد"}
            hint="انبار فیزیکی محل ورود/خروج کالا — جدا از طرف حساب"
            error={
              !(warehousesQ.data ?? []).length
                ? "هنوز انباری تعریف نشده — از منوی انبار → تنظیمات انبار بسازید"
                : undefined
            }
          >
            <Select
              value={f.watch("warehouse_id") || ""}
              onChange={(e) => {
                const id = e.target.value;
                const wh = (warehousesQ.data ?? []).find((w) => w.id === id);
                f.setValue("warehouse_id", id, { shouldDirty: true });
                f.setValue("warehouse_name", wh ? `${wh.code} — ${wh.name}` : "", { shouldDirty: true });
              }}
            >
              <option value="">انتخاب انبار…</option>
              {(warehousesQ.data ?? []).map((w) => (
                <option key={w.id} value={w.id}>
                  {w.code} — {w.name}
                </option>
              ))}
            </Select>
          </FormField>
          {showPurchaseCreditMode ? (
            <>
              <FormField
                label="طرف بستانکار (اعتبار)"
                hint="تأمین‌کننده = بدهی خرید؛ GRNI = رسید بدون فاکتور"
              >
                <Select {...f.register("credit_mode")}>
                  <option value="supplier">تأمین‌کننده / حساب پرداختنی</option>
                  <option value="grni">حساب GRNI (رسید در راه)</option>
                </Select>
              </FormField>
              <div className="sm:col-span-2">
                <FormField label="مبدأ کالا / توضیح منبع" hint="از کجا آمده؟ (اختیاری)">
                  <Input placeholder="مثال: سفارش خرید PO-12 / باربری فلان" {...f.register("source_note")} />
                </FormField>
              </div>
            </>
          ) : (
            <div className="sm:col-span-2">
              <FormField label="توضیح منبع / مرجع" hint="اختیاری">
                <Input placeholder="مثال: حواله / سفارش / توضیح" {...f.register("source_note")} />
              </FormField>
            </div>
          )}
        </>
      ) : null}
      {!withLines ? (
        <FormField label="مبلغ" error={f.formState.errors.amount?.message}>
          <MoneyInput {...f.register("amount")} />
        </FormField>
      ) : (
        <FormField label="جمع سند">
          <Input value={formatMoney(totalHint)} readOnly dir="ltr" />
        </FormField>
      )}
      <div className="sm:col-span-2">
        <FormField label="توضیحات">
          <Input {...f.register("description")} />
        </FormField>
      </div>

      {withLines ? (
        <div className="sm:col-span-2 space-y-2 rounded-xl border border-[var(--border)] p-3">
          <div className="flex items-center justify-between">
            <p className="text-sm font-medium text-secondary">اقلام سند</p>
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={() => linesArray.append({ title: "", qty: "1", unit_price: "0", note: "", item_id: "" })}
            >
              <Plus className="h-4 w-4" />
              ردیف
            </Button>
          </div>
          <div className="space-y-2">
            {linesArray.fields.map((field, index) => (
              <div key={field.id} className="grid gap-2 rounded-lg bg-[var(--surface-muted)] p-2 sm:grid-cols-12">
                <div className="sm:col-span-5">
                  <ItemCombobox
                    valueLabel={f.watch(`lines.${index}.title`) || undefined}
                    onSelect={(item) => {
                      f.setValue(`lines.${index}.item_id`, item.id, { shouldDirty: true });
                      f.setValue(`lines.${index}.title`, `${item.code} — ${item.name}`, { shouldDirty: true });
                      f.setValue(`lines.${index}.unit_price`, parseMoneyInput(item.unit_cost) || "0", {
                        shouldDirty: true,
                      });
                    }}
                    onClear={() => {
                      f.setValue(`lines.${index}.item_id`, "", { shouldDirty: true });
                      f.setValue(`lines.${index}.title`, "", { shouldDirty: true });
                    }}
                  />
                </div>
                <div className="sm:col-span-2">
                  <Input placeholder="تعداد" {...f.register(`lines.${index}.qty`)} />
                </div>
                <div className="sm:col-span-3">
                  <MoneyInput placeholder="فی" {...f.register(`lines.${index}.unit_price`)} />
                </div>
                <div className="flex items-center justify-end sm:col-span-2">
                  <Button
                    type="button"
                    size="icon"
                    variant="ghost"
                    onClick={() => linesArray.remove(index)}
                    disabled={linesArray.fields.length <= 1}
                    aria-label="حذف ردیف"
                  >
                    <Trash2 className="h-4 w-4" />
                  </Button>
                </div>
              </div>
            ))}
          </div>
        </div>
      ) : null}

      <div className="flex justify-end gap-2 sm:col-span-2">
        <Button type="button" variant="outline" onClick={onCancel}>
          انصراف
        </Button>
        <Button type="submit" disabled={pending}>
          ذخیره {title}
        </Button>
      </div>
    </form>
  );

  return (
    <div>
      <PageHeader
        title={title}
        description={description || "لیست، ثبت، ویرایش و تأیید — داده واقعی از سرویس حسابداری."}
        actions={
          <Button type="button" onClick={openCreate}>
            <Plus className="h-4 w-4" />
            {createLabel}
          </Button>
        }
      />

      {rows.length === 0 ? (
        <EmptyState
          title={`${title} ثبت نشده`}
          description={`برای شروع، «${createLabel}» را بزنید.`}
          action={
            <Button type="button" onClick={openCreate}>
              <Plus className="h-4 w-4" />
              {createLabel}
            </Button>
          }
        />
      ) : (
        <DataTable
          columns={[
            { key: "number", header: "شماره" },
            {
              key: "doc_date",
              header: "تاریخ",
              render: (r) => <JalaliDateText value={String(r.doc_date ?? "")} />,
            },
            { key: "party_name", header: partyLabel },
            ...(enableWarehouseContext
              ? [
                  ...(showMovementType
                    ? [
                        {
                          key: "movement_type",
                          header: "نوع",
                          render: (r: Record<string, unknown>) =>
                            parseMeta(r.meta_json).movement_type === "out" ? "خروج" : "ورود",
                        },
                      ]
                    : []),
                  {
                    key: "warehouse",
                    header: "انبار",
                    render: (r: Record<string, unknown>) =>
                      parseMeta(r.meta_json).warehouse_name || "—",
                  },
                  ...(showPurchaseCreditMode
                    ? [
                        {
                          key: "credit_mode",
                          header: "بستانکار",
                          render: (r: Record<string, unknown>) => {
                            const mode = parseMeta(r.meta_json).credit_mode;
                            return mode === "grni" ? "GRNI" : "تأمین‌کننده";
                          },
                        },
                      ]
                    : []),
                ]
              : []),
            {
              key: "amount",
              header: "مبلغ",
              render: (r) => formatMoney(String(r.amount ?? "0")),
            },
            {
              key: "status",
              header: "وضعیت",
              render: (r) => (
                <Badge tone={r.status === "confirmed" ? "success" : "default"}>{String(r.status)}</Badge>
              ),
            },
            {
              key: "id",
              header: "عملیات",
              render: (r) => (
                <div className="flex flex-wrap gap-1">
                  <Button type="button" size="sm" variant="ghost" onClick={() => setDetailRow(r)}>
                    <Eye className="h-4 w-4" />
                    جزئیات
                  </Button>
                  {r.status === "draft" ? (
                    <>
                      <Button type="button" size="sm" variant="outline" onClick={() => openEdit(r)}>
                        <Pencil className="h-4 w-4" />
                        ویرایش
                      </Button>
                      <Button type="button" size="sm" variant="outline" onClick={() => setConfirmId(String(r.id))}>
                        تأیید
                      </Button>
                    </>
                  ) : null}
                  {enableAccountingPost ? (
                    <Button
                      type="button"
                      size="sm"
                      onClick={() => {
                        setPreview(null);
                        postForm.reset({ profile_id: "", discount_amount: "0", tax_amount: "0" });
                        setPostRow(r);
                      }}
                    >
                      ثبت حسابداری
                    </Button>
                  ) : null}
                </div>
              ),
            },
          ]}
          rows={rows}
        />
      )}

      <PortalDialog open={createOpen} onClose={() => setCreateOpen(false)} title={createLabel} wide={withLines}>
        {renderDocForm(
          form,
          createLines,
          (d) => createM.mutate(d),
          createM.isPending,
          () => setCreateOpen(false),
          createTotal
        )}
      </PortalDialog>

      <PortalDialog
        open={!!editRow}
        onClose={() => setEditRow(null)}
        title={`ویرایش ${title}`}
        wide={withLines}
      >
        {renderDocForm(
          editForm,
          editLines,
          (d) => updateM.mutate(d),
          updateM.isPending,
          () => setEditRow(null),
          withLines ? sumLines(editForm.watch("lines")) : editForm.watch("amount") || "0",
          true
        )}
      </PortalDialog>

      <PortalDialog open={!!detailRow} onClose={() => setDetailRow(null)} title={`جزئیات ${title}`} wide>
        {detailRow ? (
          <div className="space-y-3 text-sm">
            <div className="grid gap-2 sm:grid-cols-2">
              <p>
                <span className="text-[var(--muted)]">شماره:</span> {String(detailRow.number)}
              </p>
              <p>
                <span className="text-[var(--muted)]">تاریخ:</span>{" "}
                <JalaliDateText value={String(detailRow.doc_date ?? "")} />
              </p>
              <p>
                <span className="text-[var(--muted)]">{partyLabel}:</span>{" "}
                {String(detailRow.party_name || "—")}
              </p>
              {enableWarehouseContext ? (
                <>
                  {showMovementType ? (
                    <p>
                      <span className="text-[var(--muted)]">نوع:</span>{" "}
                      {parseMeta(detailRow.meta_json).movement_type === "out" ? "خروج از انبار" : "ورود به انبار"}
                    </p>
                  ) : null}
                  <p>
                    <span className="text-[var(--muted)]">انبار:</span>{" "}
                    {parseMeta(detailRow.meta_json).warehouse_name || "—"}
                  </p>
                  {showPurchaseCreditMode ? (
                    <>
                      <p>
                        <span className="text-[var(--muted)]">طرف بستانکار:</span>{" "}
                        {parseMeta(detailRow.meta_json).credit_mode === "grni"
                          ? "حساب GRNI (رسید در راه)"
                          : "تأمین‌کننده / پرداختنی"}
                      </p>
                      <p className="sm:col-span-2">
                        <span className="text-[var(--muted)]">مبدأ کالا:</span>{" "}
                        {parseMeta(detailRow.meta_json).source_note || "—"}
                      </p>
                    </>
                  ) : parseMeta(detailRow.meta_json).source_note ? (
                    <p className="sm:col-span-2">
                      <span className="text-[var(--muted)]">مرجع:</span>{" "}
                      {parseMeta(detailRow.meta_json).source_note}
                    </p>
                  ) : null}
                </>
              ) : null}
              <p>
                <span className="text-[var(--muted)]">مبلغ:</span>{" "}
                {formatMoney(String(detailRow.amount ?? "0"))}
              </p>
              <p>
                <span className="text-[var(--muted)]">وضعیت:</span> {String(detailRow.status)}
              </p>
              <p className="sm:col-span-2">
                <span className="text-[var(--muted)]">توضیح:</span> {String(detailRow.description || "—")}
              </p>
            </div>
            {withLines ? (
              <div className="rounded-xl border border-[var(--border)] p-3">
                <p className="mb-2 font-medium">اقلام</p>
                <ul className="space-y-1">
                  {(parseMeta(detailRow.meta_json).lines ?? []).map((line, i) => (
                    <li key={i} className="flex justify-between gap-2 text-xs">
                      <span>
                        {line.title} × {line.qty}
                      </span>
                      <span dir="ltr">{formatMoney(String(Number(line.qty || 0) * Number(line.unit_price || 0)))}</span>
                    </li>
                  ))}
                  {!parseMeta(detailRow.meta_json).lines?.length ? (
                    <li className="text-[var(--muted)]">ردیفی ثبت نشده</li>
                  ) : null}
                </ul>
              </div>
            ) : null}
            <div className="flex justify-end">
              <Button type="button" variant="outline" onClick={() => setDetailRow(null)}>
                بستن
              </Button>
            </div>
          </div>
        ) : null}
      </PortalDialog>

      <PortalDialog open={!!postRow} onClose={() => setPostRow(null)} title="ثبت حسابداری سند">
        <form
          className="grid gap-3"
          onSubmit={(e) => {
            e.preventDefault();
            postM.mutate();
          }}
        >
          <p className="text-sm text-[var(--muted)]">
            سند {String(postRow?.number)} — مبلغ {formatMoney(String(postRow?.amount ?? "0"))}
          </p>
          <FormField label="پروفایل ثبت">
            <Select {...postForm.register("profile_id")}>
              <option value="">پروفایل پیش‌فرض</option>
              {profiles.map((p) => (
                <option key={p.id} value={p.id}>
                  {p.name}
                </option>
              ))}
            </Select>
          </FormField>
          {enableAccountingPost === "sales" ? (
            <div className="grid gap-3 sm:grid-cols-2">
              <FormField label="تخفیف">
                <MoneyInput {...postForm.register("discount_amount")} />
              </FormField>
              <FormField label="مالیات">
                <MoneyInput {...postForm.register("tax_amount")} />
              </FormField>
            </div>
          ) : null}
          {preview ? (
            <div className="rounded-xl bg-[var(--surface-muted)] p-3 text-sm">
              تراز: {preview.is_balanced ? "بله" : "خیر"} — بدهکار: {formatMoney(preview.total_debit)}
              {preview.total_credit ? ` — بستانکار: ${formatMoney(preview.total_credit)}` : ""}
            </div>
          ) : null}
          <div className="flex justify-end gap-2">
            <Button type="button" variant="outline" onClick={() => setPostRow(null)}>
              انصراف
            </Button>
            <Button type="button" variant="outline" disabled={previewM.isPending} onClick={() => previewM.mutate()}>
              پیش‌نمایش
            </Button>
            <Button type="submit" disabled={postM.isPending}>
              صدور سند حسابداری
            </Button>
          </div>
        </form>
      </PortalDialog>

      <ConfirmDialog
        open={!!confirmId}
        onClose={() => setConfirmId(null)}
        onConfirm={() => confirmId && confirmM.mutate(confirmId)}
        title="تأیید سند؟"
        description={
          (() => {
            const auto = policyQ.data?.auto_post;
            const key =
              module === "sales" && docType === "invoice"
                ? "sales_invoice"
                : module === "sales" && docType === "return"
                  ? "sales_return"
                  : module === "purchase" && (docType === "goods_receipt" || docType === "goods-receipts")
                    ? "purchase_goods_receipt"
                    : module === "purchase" && docType === "invoice"
                      ? "purchase_invoice"
                      : module === "purchase" && docType === "return"
                        ? "purchase_return"
                        : null;
            if (key && auto?.[key]) {
              return "با تأیید، سند عملیاتی تأیید و سند حسابداری خودکار از طریق Posting Engine صادر می‌شود.";
            }
            return "پس از تأیید، وضعیت سند به confirmed تغییر می‌کند. ثبت دفتر کل جداگانه از «ثبت حسابداری» انجام می‌شود.";
          })()
        }
        confirmLabel="تأیید"
        loading={confirmM.isPending}
      />
    </div>
  );
}
