"use client";

import { useState } from "react";
import { useForm, type FieldValues, type DefaultValues, type Resolver } 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, RotateCcw } from "lucide-react";
import type { z } from "zod";
import {
  Button,
  Dialog,
  Drawer,
  Input,
  EmptyState,
  FormField,
  ConfirmDialog,
  Textarea,
  Select,
} from "@/components/ds";
import { LoyaltyTablePage } from "@/modules/loyalty/design-system";
import { LoyaltyBreadcrumbs } from "@/modules/loyalty/components/LoyaltyBreadcrumbs";
import { LoyaltyPageLoader, LoyaltyPageError, exportToCsv } from "@/modules/loyalty/pages/shared";
import { useTenantId } from "@/hooks/useTenantId";

export type LoyaltyFieldConfig = {
  name: string;
  label: string;
  type?: "text" | "email" | "tel" | "number" | "textarea" | "select";
  options?: { value: string; label: string }[];
  required?: boolean;
  editOnly?: boolean;
  createOnly?: boolean;
};

export type LoyaltyListCrudConfig<T extends { id: string }> = {
  title: string;
  description?: string;
  breadcrumb?: string;
  resourceKey: string;
  createSchema: z.ZodTypeAny;
  editSchema: z.ZodTypeAny;
  createDefaults: DefaultValues<FieldValues>;
  fields: LoyaltyFieldConfig[];
  columns: {
    key: string;
    header: string;
    render?: (row: T) => React.ReactNode;
  }[];
  list: (tenantId: string) => Promise<T[]>;
  create: (tenantId: string, data: FieldValues) => Promise<T>;
  update?: (tenantId: string, id: string, data: FieldValues) => Promise<T>;
  remove?: (tenantId: string, id: string) => Promise<unknown>;
  restore?: (tenantId: string, id: string) => Promise<unknown>;
  exportColumns?: string[];
  filterDeleted?: boolean;
  extraActions?: (row: T, helpers: { refresh: () => void }) => React.ReactNode;
};

function renderField(
  field: LoyaltyFieldConfig,
  register: ReturnType<typeof useForm>["register"],
  mode: "create" | "edit"
) {
  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} />
      </FormField>
    );
  }
  if (field.type === "select" && field.options) {
    return (
      <FormField key={field.name} label={field.label}>
        <Select {...register(field.name)}>
          {field.options.map((o) => (
            <option key={o.value} value={o.value}>
              {o.label}
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  return (
    <FormField key={field.name} label={field.label}>
      <Input type={field.type ?? "text"} {...register(field.name)} />
    </FormField>
  );
}

export function createLoyaltyListPage<T extends { id: string; is_deleted?: boolean }>(
  config: LoyaltyListCrudConfig<T>
) {
  return function LoyaltyListPage() {
    const { tenantId } = useTenantId();
    const qc = useQueryClient();
    const [createOpen, setCreateOpen] = useState(false);
    const [editRow, setEditRow] = useState<T | null>(null);
    const [deleteId, setDeleteId] = useState<string | null>(null);
    const [page, setPage] = useState(1);
    const [selected, setSelected] = useState<Set<string>>(new Set());
    const pageSize = 20;

    const listQ = useQuery({
      queryKey: ["loyalty", tenantId, config.resourceKey],
      queryFn: () => config.list(tenantId!),
      enabled: !!tenantId,
    });

    const createForm = useForm<FieldValues>({
      resolver: zodResolver(config.createSchema as never) as Resolver<FieldValues>,
      defaultValues: config.createDefaults,
    });
    const editForm = useForm<FieldValues>({
      resolver: zodResolver(config.editSchema as never) as Resolver<FieldValues>,
    });

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

    const createM = useMutation({
      mutationFn: (d: FieldValues) => config.create(tenantId!, d),
      onSuccess: async () => {
        toast.success("رکورد ایجاد شد");
        setCreateOpen(false);
        createForm.reset(config.createDefaults);
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    const updateM = useMutation({
      mutationFn: (d: FieldValues) => config.update!(tenantId!, 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.remove!(tenantId!, id),
      onSuccess: async () => {
        toast.success("رکورد حذف شد");
        setDeleteId(null);
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    const restoreM = useMutation({
      mutationFn: (id: string) => config.restore!(tenantId!, id),
      onSuccess: async () => {
        toast.success("رکورد بازیابی شد");
        await invalidate();
      },
      onError: (e: Error) => toast.error(e.message),
    });

    const openEdit = (row: T) => {
      setEditRow(row);
      const values: FieldValues = {};
      for (const f of config.fields) {
        if (f.createOnly) continue;
        values[f.name] = (row as Record<string, unknown>)[f.name] ?? "";
      }
      if ("version" in (row as object)) {
        values.version = (row as { version?: number }).version;
      }
      editForm.reset(values);
    };

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

    let rows = listQ.data ?? [];
    if (config.filterDeleted) rows = rows.filter((r) => !r.is_deleted);

    const tableColumns = [
      ...config.columns.map((c) => ({
        key: c.key,
        header: c.header,
        render: c.render
          ? (row: Record<string, unknown>) => c.render!(row as T)
          : undefined,
      })),
      {
        key: "actions",
        header: "عملیات",
        searchable: false as const,
        render: (row: Record<string, unknown>) => {
          const r = row as T;
          return (
            <div className="flex gap-1">
              {config.extraActions?.(r, { refresh: () => void invalidate() })}
              {config.update ? (
                <Button variant="ghost" size="icon" onClick={() => openEdit(r)} aria-label="ویرایش">
                  <Pencil className="h-4 w-4" />
                </Button>
              ) : null}
              {config.remove && !r.is_deleted ? (
                <Button
                  variant="ghost"
                  size="icon"
                  onClick={() => setDeleteId(r.id)}
                  aria-label="حذف"
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              ) : null}
              {config.restore && r.is_deleted ? (
                <Button
                  variant="ghost"
                  size="icon"
                  onClick={() => restoreM.mutate(r.id)}
                  aria-label="بازیابی"
                >
                  <RotateCcw className="h-4 w-4" />
                </Button>
              ) : null}
            </div>
          );
        },
      },
    ];

    return (
      <div>
        <LoyaltyTablePage
          breadcrumbs={
            config.breadcrumb ? (
              <LoyaltyBreadcrumbs items={[{ label: config.breadcrumb }]} />
            ) : undefined
          }
          title={config.title}
          description={config.description}
          columns={tableColumns}
          rows={rows as unknown as Record<string, unknown>[]}
          page={page}
          pageSize={pageSize}
          onPageChange={setPage}
          selectedIds={selected}
          onSelectionChange={setSelected}
          bulkActions={
            config.remove && selected.size > 0 ? (
              <Button
                variant="outline"
                size="sm"
                onClick={() => {
                  selected.forEach((id) => config.remove!(tenantId, id));
                  toast.success("حذف گروهی انجام شد");
                  setSelected(new Set());
                  void invalidate();
                }}
              >
                حذف انتخاب‌شده‌ها
              </Button>
            ) : undefined
          }
          actions={
            <div className="flex gap-2">
              {config.exportColumns ? (
                <Button
                  variant="outline"
                  onClick={() =>
                    exportToCsv(
                      `${config.resourceKey}.csv`,
                      rows as unknown as Record<string, unknown>[],
                      config.exportColumns!
                    )
                  }
                >
                  خروجی CSV
                </Button>
              ) : null}
              <Button onClick={() => setCreateOpen(true)}>
                <Plus className="h-4 w-4" />
                جدید
              </Button>
            </div>
          }
          empty={
            <EmptyState
              title="موردی ثبت نشده"
              action={<Button onClick={() => setCreateOpen(true)}>ایجاد</Button>}
            />
          }
        />

        <Dialog open={createOpen} onClose={() => setCreateOpen(false)} title={`${config.title} — جدید`}>
          <form
            className="space-y-4"
            onSubmit={createForm.handleSubmit((d) => createM.mutate(d as FieldValues))}
          >
            {config.fields.map((f) => renderField(f, createForm.register, "create"))}
            <div className="flex justify-end gap-2">
              <Button type="button" variant="ghost" onClick={() => setCreateOpen(false)}>
                انصراف
              </Button>
              <Button type="submit" loading={createM.isPending}>
                ذخیره
              </Button>
            </div>
          </form>
        </Dialog>

        {config.update ? (
          <Drawer open={!!editRow} onClose={() => setEditRow(null)} title="ویرایش">
            <form
              className="space-y-4"
              onSubmit={editForm.handleSubmit((d) => updateM.mutate(d as FieldValues))}
            >
              {config.fields.map((f) => renderField(f, editForm.register, "edit"))}
              <input type="hidden" {...editForm.register("version", { valueAsNumber: true })} />
              <div className="flex justify-end gap-2">
                <Button type="button" variant="ghost" onClick={() => setEditRow(null)}>
                  انصراف
                </Button>
                <Button type="submit" loading={updateM.isPending}>
                  به‌روزرسانی
                </Button>
              </div>
            </form>
          </Drawer>
        ) : null}

        {config.remove ? (
          <ConfirmDialog
            open={!!deleteId}
            onClose={() => setDeleteId(null)}
            title="حذف رکورد"
            description="آیا از حذف این مورد مطمئن هستید؟"
            confirmLabel="حذف"
            onConfirm={() => deleteId && deleteM.mutate(deleteId)}
            loading={deleteM.isPending}
            danger
          />
        ) : null}
      </div>
    );
  };
}
