"use client";

import { useMemo, useState, type ReactNode } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Eye, Pencil, Plus, Trash2 } from "lucide-react";
import {
  PageHeader,
  Button,
  Dialog,
  Input,
  Textarea,
  DataTable,
  EmptyState,
  LoadingState,
  ErrorState,
  ConfirmDialog,
  TableToolbar,
  Select,
  Pagination,
  Tabs,
  JalaliDateText,
} from "@/components/ds";
import {
  DetailDrawer,
  Timeline,
  PermissionDeniedState,
  type TimelineItem,
} from "@/src/shared/ui";
import { useDebouncedValue, useSavedFilters } from "@/src/shared/hooks";
import { useTenantId } from "@/hooks/useTenantId";
import { BeautyBusinessApiError } from "@/modules/beauty/services/beauty-business-api";
import { useBeautyPermissions } from "@/modules/beauty/hooks/useBeautyPermissions";
import { BeautyStatusChip } from "@/modules/beauty/design-system";
import {
  OrganizationSelect,
  BranchSelect,
  StaffSelect,
  CustomerSelect,
  ServiceSelect,
  CategorySelect,
  RoomSelect,
} from "@/modules/beauty/components/BeautyComboboxes";
import { lifecycleStatusOptions } from "@/modules/beauty/constants/labels";

export type FieldType =
  | "text"
  | "textarea"
  | "number"
  | "datetime-local"
  | "select"
  | "organization"
  | "branch"
  | "staff"
  | "customer"
  | "service"
  | "category"
  | "room";

export type FieldDef = {
  name: string;
  label: string;
  type?: FieldType;
  required?: boolean;
  placeholder?: string;
  options?: { value: string; label: string }[];
  table?: boolean | ((mode: "create" | "edit") => boolean);
  form?: boolean | ((mode: "create" | "edit") => boolean);
  render?: (row: Record<string, unknown>) => ReactNode;
};

export type FilterDef = {
  id: string;
  label: string;
  options: { value: string; label: string }[];
};

export type WorkflowActionDef = {
  id: string;
  label: string;
  variant?: "default" | "outline" | "danger";
  confirmTitle?: string;
  confirmDescription?: string;
  visible?: (row: Record<string, unknown>) => boolean;
  run: (row: Record<string, unknown>, tenantId: string) => Promise<unknown>;
};

export type ListParams = {
  search?: string;
  status?: string;
  page?: number;
  pageSize?: number;
  [key: string]: string | number | undefined;
};

export type ResourceConfig = {
  storageKey: string;
  title: string;
  description?: string;
  viewPermission?: string;
  managePermission?: string;
  queryKey: string[];
  listFn: (tenantId: string, params: ListParams) => Promise<unknown[] | { items: unknown[]; total: number }>;
  createFn?: (tenantId: string, body: Record<string, unknown>) => Promise<unknown>;
  updateFn?: (tenantId: string, id: string, body: Record<string, unknown>) => Promise<unknown>;
  deleteFn?: (tenantId: string, id: string) => Promise<unknown>;
  fields: FieldDef[];
  filters?: FilterDef[];
  workflowActions?: WorkflowActionDef[];
  auditEntityType?: string;
  auditFn?: (
    tenantId: string,
    entityType: string,
    entityId: string
  ) => Promise<{ id: string; action: string; message: string | null; created_at: string }[]>;
  defaultStatusFilter?: string;
  pageSize?: number;
  createLabel?: string;
  mapCreateBody?: (values: Record<string, string>) => Record<string, unknown>;
  mapUpdateBody?: (values: Record<string, string>, row: Record<string, unknown>) => Record<string, unknown>;
  listParams?: (filters: Record<string, string>) => ListParams;
  cardTitleKey?: string;
};

function fieldVisible(f: FieldDef, mode: "create" | "edit", kind: "table" | "form") {
  const flag = kind === "table" ? f.table : f.form;
  if (flag === undefined) return kind === "table" ? f.name !== "version" : true;
  if (typeof flag === "function") return flag(mode);
  return flag;
}

function emptyValues(fields: FieldDef[]) {
  return Object.fromEntries(fields.map((f) => [f.name, ""]));
}

function rowToValues(row: Record<string, unknown>, fields: FieldDef[]) {
  const out: Record<string, string> = {};
  for (const f of fields) {
    const v = row[f.name];
    if (f.type === "datetime-local" && v) {
      const d = new Date(String(v));
      out[f.name] = Number.isNaN(d.getTime()) ? "" : d.toISOString().slice(0, 16);
    } else {
      out[f.name] = v === null || v === undefined ? "" : String(v);
    }
  }
  return out;
}

function FieldInput({
  field,
  value,
  onChange,
  organizationId,
}: {
  field: FieldDef;
  value: string;
  onChange: (v: string) => void;
  organizationId?: string;
}) {
  const type = field.type ?? "text";
  if (type === "organization")
    return <OrganizationSelect value={value} onChange={onChange} required={field.required} label={field.label} />;
  if (type === "branch")
    return (
      <BranchSelect
        value={value}
        onChange={onChange}
        required={field.required}
        label={field.label}
        organizationId={organizationId}
      />
    );
  if (type === "staff")
    return <StaffSelect value={value} onChange={onChange} required={field.required} label={field.label} />;
  if (type === "customer")
    return <CustomerSelect value={value} onChange={onChange} required={field.required} label={field.label} />;
  if (type === "service")
    return <ServiceSelect value={value} onChange={onChange} required={field.required} label={field.label} />;
  if (type === "category")
    return <CategorySelect value={value} onChange={onChange} required={field.required} label={field.label} />;
  if (type === "room")
    return (
      <RoomSelect
        value={value}
        onChange={onChange}
        required={field.required}
        label={field.label}
        organizationId={organizationId}
      />
    );
  if (type === "textarea")
    return (
      <label className="block text-sm">
        <span className="mb-1 block text-[var(--muted)]">
          {field.label}
          {field.required ? " *" : ""}
        </span>
        <Textarea
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder={field.placeholder}
          rows={3}
          required={field.required}
        />
      </label>
    );
  if (type === "select")
    return (
      <label className="block text-sm">
        <span className="mb-1 block text-[var(--muted)]">
          {field.label}
          {field.required ? " *" : ""}
        </span>
        <Select value={value} onChange={(e) => onChange(e.target.value)} required={field.required}>
          <option value="">انتخاب…</option>
          {(field.options ?? []).map((o) => (
            <option key={o.value} value={o.value}>
              {o.label}
            </option>
          ))}
        </Select>
      </label>
    );
  return (
    <label className="block text-sm">
      <span className="mb-1 block text-[var(--muted)]">
        {field.label}
        {field.required ? " *" : ""}
      </span>
      <Input
        type={type === "number" ? "number" : type === "datetime-local" ? "datetime-local" : "text"}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={field.placeholder}
        required={field.required}
      />
    </label>
  );
}

function renderCell(f: FieldDef, r: Record<string, unknown>) {
  if (f.render) return f.render(r);
  if (f.name === "status") return <BeautyStatusChip status={String(r.status ?? "")} domain="lifecycle" />;
  if (f.type === "datetime-local" && r[f.name])
    return <JalaliDateText value={String(r[f.name])} />;
  return String(r[f.name] ?? "—");
}

export function BeautyResourceWorkspace({ config, readOnly }: { config: ResourceConfig; readOnly?: boolean }) {
  const { tenantId } = useTenantId();
  const qc = useQueryClient();
  const { can, canManage } = useBeautyPermissions();
  const pageSize = config.pageSize ?? 20;

  const [search, setSearch] = useState("");
  const debouncedSearch = useDebouncedValue(search);
  const [statusFilter, setStatusFilter] = useState(config.defaultStatusFilter ?? "");
  const [extraFilters, setExtraFilters] = useState<Record<string, string>>({});
  const [page, setPage] = useState(1);
  const [viewMode, setViewMode] = useState<"table" | "cards">("table");

  const [createOpen, setCreateOpen] = useState(false);
  const [editRow, setEditRow] = useState<Record<string, unknown> | null>(null);
  const [detailRow, setDetailRow] = useState<Record<string, unknown> | null>(null);
  const [deleteRow, setDeleteRow] = useState<Record<string, unknown> | null>(null);
  const [confirmAction, setConfirmAction] = useState<{
    action: WorkflowActionDef;
    row: Record<string, unknown>;
  } | null>(null);
  const [formValues, setFormValues] = useState<Record<string, string>>(() => emptyValues(config.fields));
  const [saveFilterName, setSaveFilterName] = useState("");

  const { saved, saveFilter, removeFilter } = useSavedFilters(config.storageKey);

  const listParams = useMemo(() => {
    const base: ListParams = {
      search: debouncedSearch || undefined,
      status: statusFilter || undefined,
      page,
      pageSize,
      ...extraFilters,
    };
    return config.listParams
      ? config.listParams({ ...extraFilters, status: statusFilter, search: debouncedSearch })
      : base;
  }, [config, debouncedSearch, statusFilter, page, pageSize, extraFilters]);

  const listQ = useQuery({
    queryKey: [...config.queryKey, tenantId, listParams],
    queryFn: () => config.listFn(tenantId!, listParams),
    enabled: !!tenantId && can(config.viewPermission),
  });

  const auditQ = useQuery({
    queryKey: ["beauty", tenantId, "audit", config.auditEntityType, detailRow?.id],
    queryFn: () => config.auditFn!(tenantId!, config.auditEntityType!, String(detailRow!.id)),
    enabled: !!tenantId && !!detailRow && !!config.auditFn && !!config.auditEntityType,
  });

  const rows = useMemo(() => {
    const data = listQ.data;
    if (!data) return [];
    const items = Array.isArray(data) ? data : data.items;
    let list = items as Record<string, unknown>[];
    if (debouncedSearch && Array.isArray(data)) {
      const q = debouncedSearch.toLowerCase();
      list = list.filter((r) =>
        config.fields.some((f) => String(r[f.name] ?? "").toLowerCase().includes(q))
      );
    }
    if (statusFilter && Array.isArray(data)) {
      list = list.filter((r) => String(r.status ?? "") === statusFilter);
    }
    return list;
  }, [listQ.data, debouncedSearch, statusFilter, config.fields]);

  const total = Array.isArray(listQ.data) ? rows.length : (listQ.data?.total ?? rows.length);

  const invalidate = async () => {
    await qc.invalidateQueries({ queryKey: config.queryKey });
    await qc.invalidateQueries({ queryKey: ["beauty", tenantId, "lookups"] });
  };

  const createM = useMutation({
    mutationFn: (body: Record<string, unknown>) => config.createFn!(tenantId!, body),
    onSuccess: async () => {
      toast.success("ثبت شد");
      setCreateOpen(false);
      setFormValues(emptyValues(config.fields));
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const updateM = useMutation({
    mutationFn: ({ id, body }: { id: string; body: Record<string, unknown> }) =>
      config.updateFn!(tenantId!, id, body),
    onSuccess: async () => {
      toast.success("ذخیره شد");
      setEditRow(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const deleteM = useMutation({
    mutationFn: (id: string) => config.deleteFn!(tenantId!, id),
    onSuccess: async () => {
      toast.success("حذف شد");
      setDeleteRow(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const workflowM = useMutation({
    mutationFn: ({ action, row }: { action: WorkflowActionDef; row: Record<string, unknown> }) =>
      action.run(row, tenantId!),
    onSuccess: async () => {
      toast.success("انجام شد");
      setConfirmAction(null);
      await invalidate();
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const manageAllowed =
    !readOnly && canManage(config.viewPermission, config.managePermission) && !!config.createFn;

  if (!tenantId) return <LoadingState />;
  if (!can(config.viewPermission)) return <PermissionDeniedState />;
  if (listQ.isLoading) return <LoadingState label={`در حال بارگذاری ${config.title}…`} />;
  if (listQ.error) {
    const err = listQ.error;
    if (err instanceof BeautyBusinessApiError && err.status === 403) {
      return <PermissionDeniedState message={err.message} onRetry={() => listQ.refetch()} />;
    }
    return (
      <ErrorState
        message={err instanceof Error ? err.message : "خطا"}
        onRetry={() => listQ.refetch()}
      />
    );
  }

  const tableColumns = [
    ...config.fields
      .filter((f) => fieldVisible(f, "edit", "table"))
      .map((f) => ({
        key: f.name,
        header: f.label,
        render: (r: Record<string, unknown>) => renderCell(f, r),
      })),
    {
      key: "_actions",
      header: "عملیات",
      render: (r: Record<string, unknown>) => (
        <div className="flex flex-wrap gap-1">
          <Button
            type="button"
            variant="ghost"
            size="sm"
            onClick={() => setDetailRow(r)}
            aria-label="جزئیات"
          >
            <Eye className="h-4 w-4" />
          </Button>
          {manageAllowed && config.updateFn ? (
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => {
                setEditRow(r);
                setFormValues(rowToValues(r, config.fields));
              }}
              aria-label="ویرایش"
            >
              <Pencil className="h-4 w-4" />
            </Button>
          ) : null}
          {manageAllowed && config.deleteFn ? (
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => setDeleteRow(r)}
              aria-label="حذف"
            >
              <Trash2 className="h-4 w-4 text-red-600" />
            </Button>
          ) : null}
          {config.workflowActions?.map((a) =>
            a.visible && !a.visible(r) ? null : (
              <Button
                key={a.id}
                type="button"
                variant={a.variant ?? "outline"}
                size="sm"
                onClick={() => setConfirmAction({ action: a, row: r })}
              >
                {a.label}
              </Button>
            )
          )}
        </div>
      ),
    },
  ];

  const timelineItems: TimelineItem[] = (auditQ.data ?? []).map((log) => ({
    id: log.id,
    title: log.action,
    subtitle: log.message ?? undefined,
    timestamp: log.created_at,
  }));

  const submitCreate = () => {
    const body = config.mapCreateBody ? config.mapCreateBody(formValues) : { ...formValues };
    for (const f of config.fields) {
      if (f.required && !formValues[f.name]?.trim()) {
        toast.error(`${f.label} الزامی است`);
        return;
      }
      if (f.type === "number" && formValues[f.name]) body[f.name] = Number(formValues[f.name]);
      if (f.type === "datetime-local" && formValues[f.name]) {
        body[f.name] = new Date(formValues[f.name]).toISOString();
      }
      if (!formValues[f.name]?.trim() && !f.required) delete body[f.name];
    }
    createM.mutate(body);
  };

  const submitEdit = () => {
    if (!editRow) return;
    const body = config.mapUpdateBody
      ? config.mapUpdateBody(formValues, editRow)
      : { ...formValues, version: editRow.version };
    updateM.mutate({ id: String(editRow.id), body });
  };

  const cardKey = config.cardTitleKey ?? "name";

  return (
    <div className="space-y-4">
      <PageHeader
        title={config.title}
        description={config.description}
        actions={
          manageAllowed ? (
            <Button
              type="button"
              onClick={() => {
                setFormValues(emptyValues(config.fields));
                setCreateOpen(true);
              }}
            >
              <Plus className="h-4 w-4" />
              {config.createLabel ?? "ثبت جدید"}
            </Button>
          ) : null
        }
      />

      <Tabs
        items={[
          { id: "table", label: "جدول" },
          { id: "cards", label: "کارت" },
        ]}
        value={viewMode}
        onChange={(id) => setViewMode(id as "table" | "cards")}
      />

      <TableToolbar
        search={search}
        onSearchChange={(v) => {
          setSearch(v);
          setPage(1);
        }}
        searchPlaceholder="جستجو در لیست…"
        actions={
          <>
            {config.filters?.map((f) => (
              <Select
                key={f.id}
                value={extraFilters[f.id] ?? ""}
                onChange={(e) => {
                  setExtraFilters((prev) => ({ ...prev, [f.id]: e.target.value }));
                  setPage(1);
                }}
                className="h-10 min-w-[140px]"
              >
                <option value="">{f.label}</option>
                {f.options.map((o) => (
                  <option key={o.value} value={o.value}>
                    {o.label}
                  </option>
                ))}
              </Select>
            ))}
            <Select
              value={statusFilter}
              onChange={(e) => {
                setStatusFilter(e.target.value);
                setPage(1);
              }}
              className="h-10 min-w-[120px]"
            >
              <option value="">همه وضعیت‌ها</option>
              {lifecycleStatusOptions.map((o) => (
                <option key={o.value} value={o.value}>
                  {o.label}
                </option>
              ))}
            </Select>
          </>
        }
      />

      {saved.length > 0 ? (
        <div className="flex flex-wrap items-center gap-2 text-xs">
          <span className="text-[var(--muted)]">فیلترهای ذخیره‌شده:</span>
          {saved.map((f) => (
            <button
              key={f.id}
              type="button"
              className="rounded-full border border-[var(--border)] px-2 py-1 hover:bg-[var(--surface-muted)]"
              onClick={() => {
                setStatusFilter(f.values.status ?? "");
                setExtraFilters(f.values);
                setSearch(f.values.search ?? "");
              }}
            >
              {f.name}
              <span
                className="ms-1 text-red-500"
                onClick={(e) => {
                  e.stopPropagation();
                  removeFilter(f.id);
                }}
              >
                ×
              </span>
            </button>
          ))}
        </div>
      ) : null}

      <div className="flex flex-wrap items-end gap-2">
        <Input
          value={saveFilterName}
          onChange={(e) => setSaveFilterName(e.target.value)}
          placeholder="نام فیلتر ذخیره‌شده…"
          className="max-w-xs"
        />
        <Button
          type="button"
          variant="outline"
          size="sm"
          disabled={!saveFilterName.trim()}
          onClick={() => {
            saveFilter(saveFilterName.trim(), { status: statusFilter, search, ...extraFilters });
            setSaveFilterName("");
            toast.success("فیلتر ذخیره شد");
          }}
        >
          ذخیره فیلتر
        </Button>
        <span className="text-sm text-[var(--muted)]">{total} مورد</span>
      </div>

      {viewMode === "table" ? (
        <DataTable
          columns={tableColumns}
          rows={rows}
          empty={
            <EmptyState
              title="موردی یافت نشد"
              action={
                manageAllowed ? (
                  <Button type="button" onClick={() => setCreateOpen(true)}>
                    ثبت اولین مورد
                  </Button>
                ) : undefined
              }
            />
          }
        />
      ) : (
        <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
          {rows.length === 0 ? (
            <EmptyState title="موردی یافت نشد" />
          ) : (
            rows.map((r) => (
              <button
                key={String(r.id)}
                type="button"
                onClick={() => setDetailRow(r)}
                className="rounded-2xl border border-[var(--border)] bg-[var(--surface)] p-4 text-start transition hover:shadow-md"
              >
                <p className="font-semibold text-secondary">
                  {String(r[cardKey] ?? r.display_name ?? r.code ?? r.id)}
                </p>
                {r.status ? (
                  <BeautyStatusChip
                    status={String(r.status)}
                    domain="lifecycle"
                    className="mt-2"
                  />
                ) : null}
                <p className="mt-2 text-xs text-[var(--muted)]">{String(r.code ?? "")}</p>
              </button>
            ))
          )}
        </div>
      )}

      {!Array.isArray(listQ.data) && total > pageSize ? (
        <Pagination page={page} pageSize={pageSize} total={total} onPageChange={setPage} />
      ) : null}

      <Dialog open={createOpen} onClose={() => setCreateOpen(false)} title={config.createLabel ?? "ثبت جدید"} size="lg">
        <div className="grid gap-4 sm:grid-cols-2">
          {config.fields
            .filter((f) => fieldVisible(f, "create", "form"))
            .map((f) => (
              <FieldInput
                key={f.name}
                field={f}
                value={formValues[f.name] ?? ""}
                onChange={(v) => setFormValues((prev) => ({ ...prev, [f.name]: v }))}
                organizationId={formValues.organization_id}
              />
            ))}
        </div>
        <div className="mt-6 flex justify-end gap-2">
          <Button type="button" variant="outline" onClick={() => setCreateOpen(false)}>
            انصراف
          </Button>
          <Button type="button" onClick={submitCreate} disabled={createM.isPending}>
            {createM.isPending ? "در حال ثبت…" : "ثبت"}
          </Button>
        </div>
      </Dialog>

      <Dialog open={!!editRow} onClose={() => setEditRow(null)} title="ویرایش" size="lg">
        <div className="grid gap-4 sm:grid-cols-2">
          {config.fields
            .filter((f) => fieldVisible(f, "edit", "form") && f.name !== "code")
            .map((f) => (
              <FieldInput
                key={f.name}
                field={f}
                value={formValues[f.name] ?? ""}
                onChange={(v) => setFormValues((prev) => ({ ...prev, [f.name]: v }))}
                organizationId={formValues.organization_id}
              />
            ))}
        </div>
        <div className="mt-6 flex justify-end gap-2">
          <Button type="button" variant="outline" onClick={() => setEditRow(null)}>
            انصراف
          </Button>
          <Button type="button" onClick={submitEdit} disabled={updateM.isPending}>
            {updateM.isPending ? "در حال ذخیره…" : "ذخیره"}
          </Button>
        </div>
      </Dialog>

      <DetailDrawer
        open={!!detailRow}
        onClose={() => setDetailRow(null)}
        title="جزئیات"
        description={detailRow ? String(detailRow.code ?? detailRow.id) : undefined}
        side="left"
        width="lg"
      >
        {detailRow ? (
          <div className="space-y-4">
            <dl className="grid gap-2 text-sm">
              {config.fields.map((f) => (
                <div
                  key={f.name}
                  className="flex justify-between gap-4 border-b border-[var(--border)] py-2"
                >
                  <dt className="text-[var(--muted)]">{f.label}</dt>
                  <dd className="font-medium text-secondary">{renderCell(f, detailRow)}</dd>
                </div>
              ))}
            </dl>
            {config.auditFn && config.auditEntityType ? (
              <section>
                <h3 className="mb-3 font-semibold text-secondary">تاریخچه</h3>
                {auditQ.isLoading ? (
                  <LoadingState label="بارگذاری لاگ…" />
                ) : (
                  <Timeline items={timelineItems} />
                )}
              </section>
            ) : null}
          </div>
        ) : null}
      </DetailDrawer>

      <ConfirmDialog
        open={!!deleteRow}
        onClose={() => setDeleteRow(null)}
        onConfirm={() => deleteRow && deleteM.mutate(String(deleteRow.id))}
        title="حذف مورد"
        description="این عملیات به‌صورت نرم حذف انجام می‌شود."
        confirmLabel="حذف"
        danger
        loading={deleteM.isPending}
      />

      <ConfirmDialog
        open={!!confirmAction}
        onClose={() => setConfirmAction(null)}
        onConfirm={() => confirmAction && workflowM.mutate(confirmAction)}
        title={confirmAction?.action.confirmTitle ?? confirmAction?.action.label ?? "تأیید"}
        description={confirmAction?.action.confirmDescription}
        loading={workflowM.isPending}
      />
    </div>
  );
}
