"use client";

import { useCallback, useMemo, 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, Eye } from "lucide-react";
import Link from "next/link";
import { z } from "zod";
import {
  Button,
  Dialog,
  Drawer,
  Input,
  ConfirmDialog,
  Select,
  Textarea,
  FormField,
} from "@/components/ds";
import {
  ExperienceTablePage,
  ExperienceStatGrid,
  ExperienceStatusChip,
} from "@/modules/experience/design-system";
import {
  ExperiencePageLoader,
  ExperiencePageError,
  ExperienceEmptyState,
  exportToCsv,
} from "@/modules/experience/pages/shared";
import { useTenantId } from "@/hooks/useTenantId";
import { useExperienceLookups } from "@/modules/experience/hooks/useExperienceCapabilities";
import { useExperiencePermissions } from "@/modules/experience/hooks/useExperiencePermissions";
import { PermissionDeniedState } from "@/src/shared/ui";
import {
  formatExperienceError,
  normalizeList,
} from "@/modules/experience/services/experience-api";

export type ExperienceFieldConfig = {
  name: string;
  label: string;
  type?: "text" | "number" | "email" | "textarea" | "select" | "workspace" | "site" | "boolean";
  options?: { value: string; label: string }[];
  required?: boolean;
  createOnly?: boolean;
  editOnly?: boolean;
  placeholder?: string;
  hint?: string;
};

export type ExperienceColumnConfig = {
  key: string;
  header: string;
  type?: "status" | "datetime" | "text" | "link" | "boolean";
  linkPrefix?: string;
  render?: (row: Record<string, unknown>) => React.ReactNode;
};

type ApiResource = {
  list: (
    tenantId: string,
    params?: Record<string, string | number | undefined>
  ) => 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>;
};

export type ExperienceListConfig = {
  title: string;
  description?: string;
  breadcrumb?: string;
  resourceKey: string;
  permission?: string;
  api: ApiResource;
  columns: ExperienceColumnConfig[];
  createFields?: ExperienceFieldConfig[];
  editFields?: ExperienceFieldConfig[];
  /** When true (default), append optimistic `version` on edit. Disable for resources without version. */
  optimisticLocking?: boolean;
  /** Required list query filters — e.g. site_domains API requires site_id. */
  listRequires?: Array<"workspace" | "site">;
  readOnly?: boolean;
  detailHref?: (row: Record<string, unknown>) => string | null;
};

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

function sanitizeBody(
  fields: ExperienceFieldConfig[],
  data: FieldValues
): Record<string, unknown> {
  const out: Record<string, unknown> = {};
  for (const f of fields) {
    const raw = data[f.name];
    if (raw === undefined || raw === null || raw === "") continue;
    if (f.type === "number" || f.name === "version") {
      const n = Number(raw);
      if (!Number.isNaN(n)) out[f.name] = n;
      continue;
    }
    if (f.type === "boolean") {
      out[f.name] = raw === true || raw === "true" || raw === "1";
      continue;
    }
    out[f.name] = raw;
  }
  return out;
}

function renderCell(col: ExperienceColumnConfig, row: Record<string, unknown>) {
  if (col.render) return col.render(row);
  const val = row[col.key];
  if (col.type === "boolean") return val ? "بله" : "خیر";
  if (col.type === "status" && val) return <ExperienceStatusChip status={String(val)} />;
  if (col.type === "datetime" && val) {
    try {
      return new Date(String(val)).toLocaleString("fa-IR");
    } catch {
      return String(val);
    }
  }
  if (col.type === "link" && col.linkPrefix && row.id) {
    return (
      <Link href={`${col.linkPrefix}/${row.id}`} className="text-[var(--experience-accent)] hover:underline">
        {val != null ? String(val) : "—"}
      </Link>
    );
  }
  return val != null ? String(val) : "—";
}

function renderField(
  field: ExperienceFieldConfig,
  register: ReturnType<typeof useForm>["register"],
  mode: "create" | "edit",
  lookups: { workspaces: Record<string, unknown>[]; sites: 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} hint={field.hint}>
        <Textarea {...register(field.name)} rows={3} placeholder={field.placeholder} />
      </FormField>
    );
  }
  if (field.type === "boolean") {
    return (
      <FormField key={field.name} label={field.label} hint={field.hint}>
        <Select {...register(field.name)}>
          <option value="false">خیر</option>
          <option value="true">بله</option>
        </Select>
      </FormField>
    );
  }
  if (field.type === "select" && field.options) {
    return (
      <FormField key={field.name} label={field.label} hint={field.hint}>
        <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 === "workspace") {
    return (
      <FormField key={field.name} label={field.label} hint={field.hint}>
        <Select {...register(field.name)}>
          <option value="">انتخاب فضای کاری…</option>
          {lookups.workspaces.map((w) => (
            <option key={String(w.id)} value={String(w.id)}>
              {String(w.name)} ({String(w.code)})
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  if (field.type === "site") {
    return (
      <FormField key={field.name} label={field.label} hint={field.hint}>
        <Select {...register(field.name)}>
          <option value="">انتخاب سایت…</option>
          {lookups.sites.map((s) => (
            <option key={String(s.id)} value={String(s.id)}>
              {String(s.name)} ({String(s.code)})
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  return (
    <FormField key={field.name} label={field.label} hint={field.hint}>
      <Input
        {...register(field.name)}
        type={field.type === "number" ? "number" : field.type === "email" ? "email" : "text"}
        placeholder={field.placeholder}
      />
    </FormField>
  );
}

export function createExperienceListPage(config: ExperienceListConfig) {
  return function ExperienceListPage() {
    const { tenantId } = useTenantId();
    const qc = useQueryClient();
    const perms = useExperiencePermissions();
    const lookupsQ = useExperienceLookups(tenantId);
    const [createOpen, setCreateOpen] = useState(false);
    const [editRow, setEditRow] = useState<Record<string, unknown> | null>(null);
    const [deleteId, setDeleteId] = useState<string | null>(null);
    const [page, setPage] = useState(1);
    const [filterWorkspaceId, setFilterWorkspaceId] = useState("");
    const [filterSiteId, setFilterSiteId] = useState("");
    const pageSize = 20;
    const requires = config.listRequires ?? [];
    const optimisticLocking = config.optimisticLocking !== false;

    const createFields = config.createFields ?? [];
    const editFields = useMemo(() => {
      if (config.editFields) return config.editFields;
      const base = createFields.filter((f) => !f.createOnly);
      if (optimisticLocking) {
        return [...base, { name: "version", label: "نسخه", required: true, editOnly: true, type: "number" as const }];
      }
      return base;
    }, [config.editFields, createFields, optimisticLocking]);

    const createSchema = buildSchema(createFields);
    const editSchema = buildSchema(editFields);

    const filtersReady =
      (!requires.includes("workspace") || !!filterWorkspaceId) &&
      (!requires.includes("site") || !!filterSiteId);

    const listParams = useMemo(() => {
      const p: Record<string, string | number | undefined> = { page, page_size: pageSize };
      if (filterWorkspaceId) p.workspace_id = filterWorkspaceId;
      if (filterSiteId) p.site_id = filterSiteId;
      return p;
    }, [page, filterWorkspaceId, filterSiteId]);

    const listQ = useQuery({
      queryKey: ["experience", tenantId, config.resourceKey, listParams],
      queryFn: async () => normalizeList(await config.api.list(tenantId!, listParams)),
      enabled: !!tenantId && filtersReady,
    });

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

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

    const createM = useMutation({
      mutationFn: (d: FieldValues) =>
        config.api.create!(tenantId!, sanitizeBody(createFields, d)),
      onSuccess: () => {
        toast.success("با موفقیت ایجاد شد");
        setCreateOpen(false);
        createForm.reset();
        invalidate();
      },
      onError: (e: unknown) => toast.error(formatExperienceError(e)),
    });

    const updateM = useMutation({
      mutationFn: (d: FieldValues) =>
        config.api.update!(tenantId!, String(editRow!.id), sanitizeBody(editFields, d)),
      onSuccess: () => {
        toast.success("با موفقیت به‌روزرسانی شد");
        setEditRow(null);
        invalidate();
      },
      onError: (e: unknown) => toast.error(formatExperienceError(e)),
    });

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

    if (!tenantId || lookupsQ.isLoading) return <ExperiencePageLoader />;
    if (lookupsQ.error) {
      return <ExperiencePageError error={lookupsQ.error} onRetry={() => lookupsQ.refetch()} />;
    }
    if (config.permission && !perms.can(config.permission)) {
      return <PermissionDeniedState />;
    }

    const lookups = lookupsQ.data ?? { workspaces: [], sites: [] };
    const filteredSites = filterWorkspaceId
      ? lookups.sites.filter((s) => String(s.workspace_id) === filterWorkspaceId)
      : lookups.sites;

    if (!filtersReady) {
      return (
        <div className="space-y-4">
          <ExperienceTablePage
            title={config.title}
            description={config.description}
            breadcrumb={config.breadcrumb ?? config.title}
            columns={[]}
            rows={[]}
            page={1}
            pageSize={pageSize}
            onPageChange={() => undefined}
            actions={null}
          />
          <div className="grid gap-3 rounded-xl border border-[var(--border)] p-4 sm:grid-cols-2">
            {requires.includes("workspace") ? (
              <FormField label="فضای کاری">
                <Select
                  value={filterWorkspaceId}
                  onChange={(e) => {
                    setFilterWorkspaceId(e.target.value);
                    setFilterSiteId("");
                    setPage(1);
                  }}
                >
                  <option value="">انتخاب فضای کاری…</option>
                  {lookups.workspaces.map((w) => (
                    <option key={String(w.id)} value={String(w.id)}>
                      {String(w.name)}
                    </option>
                  ))}
                </Select>
              </FormField>
            ) : null}
            {requires.includes("site") ? (
              <FormField label="سایت">
                <Select
                  value={filterSiteId}
                  onChange={(e) => {
                    setFilterSiteId(e.target.value);
                    setPage(1);
                  }}
                >
                  <option value="">انتخاب سایت…</option>
                  {filteredSites.map((s) => (
                    <option key={String(s.id)} value={String(s.id)}>
                      {String(s.name)}
                    </option>
                  ))}
                </Select>
              </FormField>
            ) : null}
          </div>
          <ExperienceEmptyState
            title="فیلتر لازم است"
            description="برای نمایش این فهرست، فیلترهای بالا را انتخاب کنید."
          />
        </div>
      );
    }

    if (listQ.isLoading) return <ExperiencePageLoader />;
    if (listQ.error) return <ExperiencePageError error={listQ.error} onRetry={() => listQ.refetch()} />;

    const rows = listQ.data ?? [];
    const canCreate = !config.readOnly && config.api.create && (!config.permission || perms.can(config.permission.replace(".view", ".create")));
    const canEdit = !config.readOnly && config.api.update;
    const canDelete = !config.readOnly && config.api.remove;

    const tableColumns = config.columns.map((c) => ({
      ...c,
      render: (row: Record<string, unknown>) => renderCell(c, row),
    }));

    return (
      <>
        {requires.length > 0 ? (
          <div className="mb-4 grid gap-3 rounded-xl border border-[var(--border)] p-4 sm:grid-cols-2">
            {requires.includes("workspace") ? (
              <FormField label="فضای کاری">
                <Select
                  value={filterWorkspaceId}
                  onChange={(e) => {
                    setFilterWorkspaceId(e.target.value);
                    setFilterSiteId("");
                    setPage(1);
                  }}
                >
                  <option value="">انتخاب فضای کاری…</option>
                  {lookups.workspaces.map((w) => (
                    <option key={String(w.id)} value={String(w.id)}>
                      {String(w.name)}
                    </option>
                  ))}
                </Select>
              </FormField>
            ) : null}
            {requires.includes("site") ? (
              <FormField label="سایت">
                <Select
                  value={filterSiteId}
                  onChange={(e) => {
                    setFilterSiteId(e.target.value);
                    setPage(1);
                  }}
                >
                  <option value="">انتخاب سایت…</option>
                  {filteredSites.map((s) => (
                    <option key={String(s.id)} value={String(s.id)}>
                      {String(s.name)}
                    </option>
                  ))}
                </Select>
              </FormField>
            ) : null}
          </div>
        ) : null}

        <ExperienceTablePage
          title={config.title}
          description={config.description}
          breadcrumb={config.breadcrumb ?? config.title}
          columns={tableColumns}
          rows={rows}
          page={page}
          pageSize={pageSize}
          onPageChange={setPage}
          loading={listQ.isFetching}
          actions={
            <div className="flex flex-wrap gap-2">
              <Button variant="outline" size="sm" onClick={() => listQ.refetch()}>
                <RefreshCw className="ml-1 h-4 w-4" />
                بروزرسانی
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={() => exportToCsv(config.title, rows, config.columns.map((c) => c.key))}
              >
                <Download className="ml-1 h-4 w-4" />
                خروجی CSV
              </Button>
              {canCreate ? (
                <Button size="sm" onClick={() => setCreateOpen(true)}>
                  <Plus className="ml-1 h-4 w-4" />
                  ایجاد
                </Button>
              ) : null}
            </div>
          }
        />

        <ExperienceStatGrid
          stats={[
            { label: "کل", value: String(rows.length) },
            {
              label: "فعال",
              value: String(
                rows.filter((r) => r.status === "active" || r.publish_status === "published" || r.is_verified === true).length
              ),
            },
          ]}
        />

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

        <Drawer open={!!editRow} onClose={() => setEditRow(null)} title={`ویرایش ${config.title}`}>
          {editRow ? (
            <form className="space-y-4" onSubmit={editForm.handleSubmit((d) => updateM.mutate(d))}>
              {editFields.map((f) => renderField(f, editForm.register, "edit", lookups))}
              <div className="flex justify-end gap-2">
                <Button type="button" variant="outline" onClick={() => setEditRow(null)}>انصراف</Button>
                <Button type="submit" loading={updateM.isPending}>ذخیره</Button>
              </div>
            </form>
          ) : null}
        </Drawer>

        <ConfirmDialog
          open={!!deleteId}
          onClose={() => setDeleteId(null)}
          title="حذف"
          description="آیا از حذف این مورد اطمینان دارید؟"
          confirmLabel="حذف"
          danger
          onConfirm={() => deleteId && deleteM.mutate(deleteId)}
        />

        {rows.length > 0 && (canEdit || canDelete || config.detailHref) ? (
          <div className="mt-4 overflow-x-auto rounded-xl border border-[var(--border)]">
            <table className="w-full text-xs">
              <thead>
                <tr className="bg-[var(--surface-muted)]">
                  <th className="px-3 py-2 text-right">عملیات سریع</th>
                </tr>
              </thead>
              <tbody>
                {rows.slice(0, 8).map((row) => (
                  <tr key={String(row.id)} className="border-t border-[var(--border)]">
                    <td className="flex flex-wrap gap-1 px-3 py-2">
                      {config.detailHref?.(row) ? (
                        <Link href={config.detailHref!(row)!}>
                          <Button variant="ghost" size="sm"><Eye className="h-3 w-3" /></Button>
                        </Link>
                      ) : null}
                      {canEdit ? (
                        <Button
                          variant="ghost"
                          size="sm"
                          onClick={() => {
                            setEditRow(row);
                            editForm.reset(
                              Object.fromEntries(
                                editFields.map((f) => [
                                  f.name,
                                  f.type === "boolean"
                                    ? row[f.name] === true
                                      ? "true"
                                      : "false"
                                    : String(row[f.name] ?? ""),
                                ])
                              ) as DefaultValues<FieldValues>
                            );
                          }}
                        >
                          <Pencil className="h-3 w-3" />
                        </Button>
                      ) : null}
                      {canDelete ? (
                        <Button variant="ghost" size="sm" onClick={() => setDeleteId(String(row.id))}>
                          <Trash2 className="h-3 w-3" />
                        </Button>
                      ) : null}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : null}
      </>
    );
  };
}
