"use client";

import { useEffect, useState } from "react";
import type { ChangeEvent } from "react";
import { useParams, useRouter } from "next/navigation";
import { Controller, useFieldArray, useForm, useWatch } 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 { Plus, Trash2 } from "lucide-react";
import { accountingApi } from "@/src/modules/accounting/services/accounting-api";
import { useTenantId } from "@/hooks/useTenantId";
import { formatMoney, toRialInteger } from "@/lib/utils";
import { lineBothSidesError, sumVoucherLines, unbalancedMessage } from "@/lib/voucher-balance";
import {
  PageHeader,
  Button,
  Badge,
  DataTable,
  LoadingState,
  ErrorState,
  ConfirmDialog,
  Card,
  CardContent,
  JalaliDateText,
  DatePicker,
  Input,
  Label,
  FieldError,
  Select,
  MoneyInput,
} from "@/src/shared/ui";

const STATUS_FA: Record<string, string> = {
  draft: "پیش‌نویس",
  validated: "اعتبارسنجی‌شده",
  posted: "ثبت قطعی",
  reversed: "برگشتی",
  cancelled: "لغو شده",
};

const lineSchema = z.object({
  account_id: z.string().uuid("حساب معتبر انتخاب کنید"),
  debit: z.string().min(1),
  credit: z.string().min(1),
  description: z.string().optional(),
  cost_center_id: z.string().optional(),
  project_id: z.string().optional(),
});

const editSchema = z.object({
  voucher_date: z.string().min(1),
  description: z.string().optional(),
  lines: z.array(lineSchema).min(2, "حداقل دو ردیف لازم است"),
});

type EditForm = z.infer<typeof editSchema>;

export function VoucherDetailPage() {
  const params = useParams<{ id: string }>();
  const id = params.id;
  const { tenantId } = useTenantId();
  const qc = useQueryClient();
  const router = useRouter();
  const [confirm, setConfirm] = useState<"post" | "reverse" | "reverse-edit" | "cancel" | null>(
    null
  );
  const [editing, setEditing] = useState(false);

  const voucherQ = useQuery({
    queryKey: ["accounting", tenantId, "voucher", id],
    queryFn: () => accountingApi.vouchers.get(tenantId!, id),
    enabled: !!tenantId && !!id,
  });
  const accountsQ = useQuery({
    queryKey: ["accounting", tenantId, "accounts"],
    queryFn: () => accountingApi.accounts.list(tenantId!),
    enabled: !!tenantId,
  });
  const costCentersQ = useQuery({
    queryKey: ["accounting", tenantId, "cost-centers"],
    queryFn: () => accountingApi.costCenters.list(tenantId!),
    enabled: !!tenantId,
  });
  const projectsQ = useQuery({
    queryKey: ["accounting", tenantId, "projects"],
    queryFn: () => accountingApi.projects.list(tenantId!),
    enabled: !!tenantId,
  });

  const editForm = useForm<EditForm>({
    resolver: zodResolver(editSchema),
    defaultValues: { voucher_date: "", description: "", lines: [] },
  });
  const { fields, append, remove } = useFieldArray({ control: editForm.control, name: "lines" });

  useEffect(() => {
    const v = voucherQ.data;
    if (!v || v.status !== "draft") return;
    editForm.reset({
      voucher_date: v.voucher_date,
      description: v.description ?? "",
      lines: v.lines.map((l) => ({
        account_id: l.account_id,
        debit: toRialInteger(l.debit) || "0",
        credit: toRialInteger(l.credit) || "0",
        description: l.description ?? "",
        cost_center_id: l.cost_center_id ?? "",
        project_id: l.project_id ?? "",
      })),
    });
  }, [voucherQ.data, editForm]);

  const invalidate = async () => {
    await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "voucher", id] });
    await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "vouchers"] });
  };

  const updateM = useMutation({
    mutationFn: (data: EditForm) => {
      const bal = sumVoucherLines(data.lines);
      if (!bal.isBalanced) throw new Error(unbalancedMessage(bal.debit, bal.credit));
      for (let i = 0; i < data.lines.length; i++) {
        const err = lineBothSidesError(data.lines[i].debit, data.lines[i].credit);
        if (err) throw new Error(`ردیف ${i + 1}: ${err}`);
      }
      return accountingApi.vouchers.update(tenantId!, id, {
        voucher_date: data.voucher_date,
        description: data.description || undefined,
        lines: data.lines.map((l) => ({
          account_id: l.account_id,
          debit: toRialInteger(l.debit) || "0",
          credit: toRialInteger(l.credit) || "0",
          description: l.description || undefined,
          cost_center_id: l.cost_center_id || null,
          project_id: l.project_id || null,
        })),
      });
    },
    onSuccess: async () => {
      toast.success("سند به‌روز شد");
      setEditing(false);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const validateM = useMutation({
    mutationFn: () => accountingApi.vouchers.validate(tenantId!, id),
    onSuccess: async () => {
      toast.success("سند اعتبارسنجی شد");
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });
  const postM = useMutation({
    mutationFn: () => accountingApi.vouchers.post(tenantId!, id, "manual"),
    onSuccess: async () => {
      toast.success("سند ثبت قطعی شد");
      setConfirm(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });
  const reverseM = useMutation({
    mutationFn: () => accountingApi.vouchers.reverse(tenantId!, id),
    onSuccess: async () => {
      toast.success("سند برگشت خورد (سند معکوس ثبت شد)");
      setConfirm(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });
  const reverseEditM = useMutation({
    mutationFn: () => accountingApi.vouchers.reverseAndEdit(tenantId!, id),
    onSuccess: async (draft) => {
      toast.success("سند برگشت خورد؛ پیش‌نویس اصلاحی باز شد");
      setConfirm(null);
      await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "vouchers"] });
      router.push(`/accounting/vouchers/${draft.id}`);
    },
    onError: (e: Error) => toast.error(e.message),
  });
  const cancelM = useMutation({
    mutationFn: () => accountingApi.vouchers.cancel(tenantId!, id),
    onSuccess: async () => {
      toast.success("سند لغو شد");
      setConfirm(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const watchedEditLines = useWatch({ control: editForm.control, name: "lines" });
  const balance = sumVoucherLines(watchedEditLines);

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

  const v = voucherQ.data!;
  const accountMap = new Map((accountsQ.data ?? []).map((a) => [a.id, `${a.code} — ${a.name}`]));
  const postable = (accountsQ.data ?? []).filter((a) => a.is_postable);
  const activeCostCenters = (costCentersQ.data ?? []).filter((c) => c.is_active);
  const activeProjects = (projectsQ.data ?? []).filter((p) => p.is_active);

  const isDraft = v.status === "draft";

  return (
    <div>
      <PageHeader
        title={`سند ${v.voucher_number}`}
        description={v.description || "جزئیات سند و اقدامات Posting Engine"}
        actions={
          <div className="flex flex-wrap gap-2">
            <Button type="button" variant="outline" onClick={() => router.push("/accounting/vouchers")}>
              بازگشت
            </Button>
            {isDraft ? (
              <Button type="button" variant="outline" onClick={() => setEditing((e) => !e)}>
                {editing ? "لغو ویرایش" : "ویرایش"}
              </Button>
            ) : null}
            {v.status === "draft" || v.status === "validated" ? (
              <Button type="button" variant="outline" disabled={validateM.isPending} onClick={() => validateM.mutate()}>
                اعتبارسنجی
              </Button>
            ) : null}
            {v.status === "draft" || v.status === "validated" ? (
              <Button type="button" onClick={() => setConfirm("post")}>
                ثبت قطعی
              </Button>
            ) : null}
            {v.status === "posted" ? (
              <>
                <Button type="button" variant="outline" onClick={() => setConfirm("reverse")}>
                  فقط برگشت
                </Button>
                <Button type="button" onClick={() => setConfirm("reverse-edit")}>
                  برگشت و ویرایش
                </Button>
              </>
            ) : null}
            {v.status === "draft" || v.status === "validated" ? (
              <Button type="button" variant="danger" onClick={() => setConfirm("cancel")}>
                لغو / حذف
              </Button>
            ) : null}
          </div>
        }
      />

      <div className="mb-6 grid gap-4 sm:grid-cols-4">
        <Card>
          <CardContent className="pt-5">
            <p className="text-xs text-[var(--muted)]">وضعیت</p>
            <Badge className="mt-2" tone={v.status === "posted" ? "success" : "default"}>
              {STATUS_FA[v.status] ?? v.status}
            </Badge>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="pt-5">
            <p className="text-xs text-[var(--muted)]">تاریخ</p>
            <p className="mt-2 font-medium">
              <JalaliDateText value={v.voucher_date} />
            </p>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="pt-5">
            <p className="text-xs text-[var(--muted)]">جمع بدهکار</p>
            <p className="mt-2 font-medium">{formatMoney(v.total_debit)}</p>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="pt-5">
            <p className="text-xs text-[var(--muted)]">جمع بستانکار</p>
            <p className="mt-2 font-medium">{formatMoney(v.total_credit)}</p>
          </CardContent>
        </Card>
      </div>

      {isDraft && editing ? (
        <form className="space-y-4" onSubmit={editForm.handleSubmit((d) => updateM.mutate(d))}>
          <Card>
            <CardContent className="grid gap-4 pt-6 sm:grid-cols-2">
              <div>
                <Label>تاریخ</Label>
                <Controller
                  control={editForm.control}
                  name="voucher_date"
                  render={({ field }) => (
                    <DatePicker
                      className="mt-1"
                      value={field.value}
                      onChange={field.onChange}
                      onBlur={field.onBlur}
                      name={field.name}
                    />
                  )}
                />
                <FieldError>{editForm.formState.errors.voucher_date?.message}</FieldError>
              </div>
              <div>
                <Label>شرح</Label>
                <Input className="mt-1" {...editForm.register("description")} />
              </div>
            </CardContent>
          </Card>

          <Card>
            <CardContent className="space-y-3 pt-6">
              <div className="flex items-center justify-between">
                <h2 className="font-semibold text-secondary">ردیف‌های سند</h2>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() =>
                    append({
                      account_id: "",
                      debit: "0",
                      credit: "0",
                      description: "",
                      cost_center_id: "",
                      project_id: "",
                    })
                  }
                >
                  <Plus className="h-4 w-4" />
                  ردیف
                </Button>
              </div>
              {fields.map((field, index) => {
                const lineErr = lineBothSidesError(
                  watchedEditLines?.[index]?.debit ?? "0",
                  watchedEditLines?.[index]?.credit ?? "0"
                );
                return (
                <div
                  key={field.id}
                  className={`grid gap-2 rounded-xl border p-3 sm:grid-cols-12 ${
                    lineErr ? "border-red-300 bg-red-50/40" : "border-[var(--border)]"
                  }`}
                >
                  <div className="sm:col-span-3">
                    <Label>حساب</Label>
                    <Select className="mt-1" {...editForm.register(`lines.${index}.account_id`)}>
                      <option value="">انتخاب</option>
                      {postable.map((a) => (
                        <option key={a.id} value={a.id}>
                          {a.code} — {a.name}
                        </option>
                      ))}
                    </Select>
                  </div>
                  <div className="sm:col-span-2">
                    <Label>بدهکار</Label>
                    <Controller
                      control={editForm.control}
                      name={`lines.${index}.debit`}
                      render={({ field }) => (
                        <MoneyInput
                          className="mt-1"
                          name={field.name}
                          ref={field.ref}
                          value={field.value ?? "0"}
                          onBlur={field.onBlur}
                          onChange={(e) => {
                            const next =
                              typeof e === "object" && e && "target" in e
                                ? String((e as ChangeEvent<HTMLInputElement>).target.value)
                                : String(e ?? "0");
                            field.onChange(next);
                          }}
                        />
                      )}
                    />
                  </div>
                  <div className="sm:col-span-2">
                    <Label>بستانکار</Label>
                    <Controller
                      control={editForm.control}
                      name={`lines.${index}.credit`}
                      render={({ field }) => (
                        <MoneyInput
                          className="mt-1"
                          name={field.name}
                          ref={field.ref}
                          value={field.value ?? "0"}
                          onBlur={field.onBlur}
                          onChange={(e) => {
                            const next =
                              typeof e === "object" && e && "target" in e
                                ? String((e as ChangeEvent<HTMLInputElement>).target.value)
                                : String(e ?? "0");
                            field.onChange(next);
                          }}
                        />
                      )}
                    />
                  </div>
                  <div className="sm:col-span-2">
                    <Label>مرکز هزینه</Label>
                    <Select className="mt-1" {...editForm.register(`lines.${index}.cost_center_id`)}>
                      <option value="">—</option>
                      {activeCostCenters.map((c) => (
                        <option key={c.id} value={c.id}>
                          {c.code} — {c.name}
                        </option>
                      ))}
                    </Select>
                  </div>
                  <div className="sm:col-span-2">
                    <Label>پروژه</Label>
                    <Select className="mt-1" {...editForm.register(`lines.${index}.project_id`)}>
                      <option value="">—</option>
                      {activeProjects.map((p) => (
                        <option key={p.id} value={p.id}>
                          {p.code} — {p.name}
                        </option>
                      ))}
                    </Select>
                  </div>
                  <div className="flex items-end sm:col-span-1">
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      disabled={fields.length <= 2}
                      onClick={() => remove(index)}
                      aria-label="حذف ردیف"
                    >
                      <Trash2 className="h-4 w-4" />
                    </Button>
                  </div>
                  {lineErr ? (
                    <p className="sm:col-span-12 text-xs text-red-700">ردیف {index + 1}: {lineErr}</p>
                  ) : null}
                </div>
                );
              })}
              <FieldError>
                {editForm.formState.errors.lines?.message || editForm.formState.errors.lines?.root?.message}
              </FieldError>
            </CardContent>
          </Card>

          <div
            className={`rounded-xl border p-3 text-sm ${
              balance.isBalanced
                ? "border-emerald-200 bg-emerald-50 text-emerald-800"
                : "border-red-200 bg-red-50 text-red-800"
            }`}
          >
            <div className="flex flex-wrap gap-4">
              <span>جمع بدهکار: {formatMoney(String(balance.debit))}</span>
              <span>جمع بستانکار: {formatMoney(String(balance.credit))}</span>
              <span>اختلاف: {formatMoney(String(Math.abs(balance.difference)))}</span>
              <span className="font-semibold">
                {balance.isBalanced
                  ? "متوازن ✓"
                  : !balance.hasAmount
                    ? "مبالغ ردیف‌ها را وارد کنید"
                    : "نامتوازن — ذخیره مجاز نیست"}
              </span>
            </div>
            {balance.hasAmount && !balance.isBalanced ? (
              <p className="mt-2 text-xs">{unbalancedMessage(balance.debit, balance.credit)}</p>
            ) : null}
          </div>
          <div className="flex justify-end gap-2">
            <Button type="button" variant="outline" onClick={() => setEditing(false)}>
              انصراف
            </Button>
            <Button type="submit" disabled={updateM.isPending || !balance.isBalanced || (watchedEditLines ?? []).some((l) => !!lineBothSidesError(l.debit, l.credit))}>
              ذخیره تغییرات
            </Button>
          </div>
        </form>
      ) : (
        <DataTable
          columns={[
            { key: "line_number", header: "#" },
            {
              key: "account_id",
              header: "حساب",
              render: (r) => accountMap.get(String(r.account_id)) || String(r.account_id),
            },
            { key: "debit", header: "بدهکار", render: (r) => formatMoney(String(r.debit)) },
            { key: "credit", header: "بستانکار", render: (r) => formatMoney(String(r.credit)) },
            {
              key: "cost_center_id",
              header: "مرکز هزینه",
              render: (r) => {
                const cid = r.cost_center_id ? String(r.cost_center_id) : "";
                if (!cid) return "—";
                const cc = (costCentersQ.data ?? []).find((c) => c.id === cid);
                return cc ? `${cc.code} — ${cc.name}` : "—";
              },
            },
            { key: "description", header: "شرح" },
          ]}
          rows={(v.lines ?? []) as unknown as Record<string, unknown>[]}
        />
      )}

      <ConfirmDialog
        open={confirm === "post"}
        onClose={() => setConfirm(null)}
        title="ثبت قطعی سند؟"
        description="پس از ثبت، سند قابل ویرایش مستقیم نیست. در صورت اشتباه می‌توانید «برگشت و ویرایش» کنید."
        confirmLabel="ثبت قطعی"
        loading={postM.isPending}
        onConfirm={() => postM.mutate()}
      />
      <ConfirmDialog
        open={confirm === "reverse"}
        onClose={() => setConfirm(null)}
        title="فقط برگشت سند؟"
        description="یک سند معکوس ثبت می‌شود و این سند به وضعیت برگشتی می‌رود. برای اصلاح محتوا از «برگشت و ویرایش» استفاده کنید."
        confirmLabel="تأیید برگشت"
        danger
        loading={reverseM.isPending}
        onConfirm={() => reverseM.mutate()}
      />
      <ConfirmDialog
        open={confirm === "reverse-edit"}
        onClose={() => setConfirm(null)}
        title="برگشت و باز کردن برای ویرایش؟"
        description="سند قطعی برگشت می‌خورد، سند معکوس ثبت می‌شود، و یک پیش‌نویس جدید با همان ردیف‌ها برای اصلاح باز می‌شود. این کار قابل بازگشت آسان نیست."
        confirmLabel="برگشت و ویرایش"
        danger
        loading={reverseEditM.isPending}
        onConfirm={() => reverseEditM.mutate()}
      />
      <ConfirmDialog
        open={confirm === "cancel"}
        onClose={() => setConfirm(null)}
        title="لغو / حذف سند پیش‌نویس؟"
        description="سند پیش‌نویس لغو می‌شود و دیگر قابل ثبت قطعی نیست. اسناد قطعی‌شده قابل حذف فیزیکی نیستند."
        confirmLabel="لغو سند"
        danger
        loading={cancelM.isPending}
        onConfirm={() => cancelM.mutate()}
      />
    </div>
  );
}
