"use client";

/**
 * Typed operational document workflows for domains without dedicated engines yet.
 * Still real /ops API — NOT the generic number/party/amount stub.
 */
import { useMemo, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Plus } from "lucide-react";
import { toast } from "sonner";
import { z } from "zod";
import { accountingApi } from "@/lib/accounting-api";
import { useTenantId } from "@/hooks/useTenantId";
import { formatMoney, parseMoneyInput } from "@/lib/utils";
import {
  Badge,
  Button,
  DataTable,
  DatePicker,
  Dialog,
  EmptyState,
  ErrorState,
  FormField,
  Input,
  JalaliDateText,
  LoadingState,
  MoneyInput,
  PageHeader,
  Select,
} from "@/components/ds";
import { PartyCombobox } from "@/components/accounting/EntityCombobox";

type FieldDef =
  | { key: string; label: string; kind: "text" | "money" | "date" | "select"; options?: { value: string; label: string }[]; required?: boolean }
  | { key: string; label: string; kind: "party"; module?: string; required?: boolean };

export function SpecializedOpsPage({
  title,
  description,
  module,
  docType,
  createLabel,
  fields,
  amountKey = "amount",
}: {
  title: string;
  description: string;
  module: string;
  docType: string;
  createLabel: string;
  fields: FieldDef[];
  amountKey?: string;
}) {
  const { tenantId } = useTenantId();
  const qc = useQueryClient();
  const [open, setOpen] = useState(false);

  const shape: Record<string, z.ZodTypeAny> = {
    number: z.string().optional(),
    doc_date: z.string().min(1, "تاریخ الزامی است"),
    party_name: z.string().optional(),
    party_id: z.string().optional(),
    description: z.string().optional(),
  };
  for (const f of fields) {
    if (f.kind === "party") continue;
    shape[f.key] = f.required === false ? z.string().optional() : z.string().min(1, `${f.label} الزامی است`);
  }
  const schema = z.object(shape);
  type Values = z.infer<typeof schema>;

  const defaults = useMemo(() => {
    const d: Record<string, string> = {
      number: "",
      doc_date: new Date().toISOString().slice(0, 10),
      party_name: "",
      party_id: "",
      description: "",
    };
    for (const f of fields) {
      if (f.kind === "party") continue;
      d[f.key] = f.kind === "money" ? "0" : f.kind === "date" ? new Date().toISOString().slice(0, 10) : "";
    }
    return d as Values;
  }, [fields]);

  const form = useForm<Values>({ resolver: zodResolver(schema), defaultValues: defaults });

  const listQ = useQuery({
    queryKey: ["accounting", tenantId, "ops-docs", module, docType],
    queryFn: () => accountingApi.ops.listDocuments(tenantId!, module, docType),
    enabled: !!tenantId,
  });

  const createM = useMutation({
    mutationFn: (v: Values) => {
      const meta: Record<string, string> = {};
      for (const f of fields) {
        if (f.kind === "party") continue;
        const raw = String((v as Record<string, string>)[f.key] ?? "");
        meta[f.key] = f.kind === "money" ? parseMoneyInput(raw) || "0" : raw;
      }
      const amount = parseMoneyInput(String((v as Record<string, string>)[amountKey] ?? meta[amountKey] ?? "0")) || "0";
      return accountingApi.ops.createDocument(tenantId!, {
        module,
        doc_type: docType,
        number: String(v.number || "").trim() || undefined,
        doc_date: String(v.doc_date),
        party_name: v.party_name || undefined,
        party_id: v.party_id || undefined,
        amount,
        description: v.description || undefined,
        status: "draft",
        meta_json: JSON.stringify(meta),
      });
    },
    onSuccess: async () => {
      toast.success(`${title} ثبت شد`);
      setOpen(false);
      form.reset(defaults);
      await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "ops-docs", module, docType] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const openCreate = async () => {
    form.reset(defaults);
    setOpen(true);
    try {
      const seq = await accountingApi.setup.peekNumber(tenantId!, `ops.${module}.${docType}`);
      form.setValue("number" as never, seq.preview as never);
    } catch {
      /* BE allocates on blank */
    }
  };
  const confirmM = useMutation({
    mutationFn: (id: string) => accountingApi.ops.confirmDocument(tenantId!, id),
    onSuccess: async () => {
      toast.success("تأیید شد");
      await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "ops-docs", module, docType] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

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

  return (
    <div>
      <PageHeader
        title={title}
        description={description}
        actions={
          <Button type="button" onClick={() => void 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: "طرف حساب" },
          { 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) =>
              r.status === "draft" ? (
                <Button size="sm" variant="outline" onClick={() => confirmM.mutate(String(r.id))}>
                  تأیید
                </Button>
              ) : null,
          },
        ]}
        rows={(listQ.data ?? []) as unknown as Record<string, unknown>[]}
        empty={
          <EmptyState
            title={`${title} ثبت نشده`}
            action={
              <Button type="button" onClick={() => void openCreate()}>
                <Plus className="h-4 w-4" />
                {createLabel}
              </Button>
            }
          />
        }
      />
      <Dialog open={open} onClose={() => setOpen(false)} title={createLabel} size="lg">
        <form className="grid gap-3 sm:grid-cols-2" onSubmit={form.handleSubmit((v) => createM.mutate(v))}>
          <FormField label="شماره" error={form.formState.errors.number?.message as string | undefined}>
            <Input {...form.register("number")} placeholder="خودکار از سیستم" />
          </FormField>
          <FormField label="تاریخ">
            <Controller
              control={form.control}
              name="doc_date"
              render={({ field }) => <DatePicker value={field.value} onChange={field.onChange} onBlur={field.onBlur} name={field.name} />}
            />
          </FormField>
          {fields.map((f) => {
            if (f.kind === "party") {
              return (
                <FormField key={f.key} label={f.label} className="sm:col-span-2">
                  <PartyCombobox
                    module={f.module}
                    valueName={(form.watch("party_name") as string) || undefined}
                    onChange={(party) => {
                      form.setValue("party_name", party?.name || "");
                      form.setValue("party_id", party?.id || "");
                    }}
                  />
                </FormField>
              );
            }
            if (f.kind === "money") {
              return (
                <FormField key={f.key} label={f.label}>
                  <MoneyInput {...form.register(f.key as keyof Values)} />
                </FormField>
              );
            }
            if (f.kind === "date") {
              return (
                <FormField key={f.key} label={f.label}>
                  <Controller
                    control={form.control}
                    name={f.key as keyof Values}
                    render={({ field }) => (
                      <DatePicker value={String(field.value || "")} onChange={field.onChange} onBlur={field.onBlur} name={field.name} />
                    )}
                  />
                </FormField>
              );
            }
            if (f.kind === "select") {
              return (
                <FormField key={f.key} label={f.label}>
                  <Select {...form.register(f.key as keyof Values)}>
                    <option value="">انتخاب…</option>
                    {(f.options ?? []).map((o) => (
                      <option key={o.value} value={o.value}>
                        {o.label}
                      </option>
                    ))}
                  </Select>
                </FormField>
              );
            }
            return (
              <FormField key={f.key} label={f.label}>
                <Input {...form.register(f.key as keyof Values)} />
              </FormField>
            );
          })}
          <FormField label="توضیحات" className="sm:col-span-2">
            <Input {...form.register("description")} />
          </FormField>
          <div className="flex justify-end gap-2 sm:col-span-2">
            <Button type="button" variant="outline" onClick={() => setOpen(false)}>
              انصراف
            </Button>
            <Button type="submit" disabled={createM.isPending}>
              ذخیره
            </Button>
          </div>
        </form>
      </Dialog>
    </div>
  );
}
