"use client";

import { useCallback, 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 { CommunicationTablePage, CommunicationStatGrid } from "@/modules/communication/design-system";
import {
  CommunicationPageLoader,
  CommunicationPageError,
  exportToCsv,
} from "@/modules/communication/pages/shared";
import { useTenantId } from "@/hooks/useTenantId";
import { useCommunicationLookups } from "@/modules/communication/hooks/useCommunicationCapabilities";
import { useCommunicationPermissions } from "@/modules/communication/hooks/useCommunicationPermissions";
import { CommunicationStatusChip } from "@/modules/communication/design-system";
import { PermissionDeniedState } from "@/src/shared/ui";

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

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

type ApiResource = {
  list: (
    tenantId: string,
    params?: Record<string, string | number | undefined>
  ) => Promise<Record<string, unknown>[] | { items: Record<string, unknown>[]; total: number }>;
  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 CommunicationListConfig = {
  title: string;
  description?: string;
  breadcrumb?: string;
  resourceKey: string;
  permission?: string;
  api: ApiResource;
  columns: CommunicationColumnConfig[];
  createFields?: CommunicationFieldConfig[];
  editFields?: CommunicationFieldConfig[];
  readOnly?: boolean;
  detailHref?: (row: Record<string, unknown>) => string | null;
  rowActions?: {
    label: string;
    onClick: (tenantId: string, row: Record<string, unknown>) => Promise<void>;
    variant?: "default" | "outline" | "danger";
  }[];
};

function buildSchema(fields: CommunicationFieldConfig[]) {
  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 normalizeList(
  data: Record<string, unknown>[] | { items: Record<string, unknown>[]; total: number }
): Record<string, unknown>[] {
  if (Array.isArray(data)) return data;
  return data.items ?? [];
}

function renderCell(col: CommunicationColumnConfig, row: Record<string, unknown>) {
  if (col.render) return col.render(row);
  const val = row[col.key];
  if (col.type === "status" && val) return <CommunicationStatusChip 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(--communication-accent)] hover:underline">
        {val != null ? String(val) : "—"}
      </Link>
    );
  }
  return val != null ? String(val) : "—";
}

function renderField(
  field: CommunicationFieldConfig,
  register: ReturnType<typeof useForm>["register"],
  mode: "create" | "edit",
  lookups: { organizations: Record<string, unknown>[]; hubs: 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}>
        <Textarea {...register(field.name)} rows={3} placeholder={field.placeholder} />
      </FormField>
    );
  }
  if (field.type === "select" && field.options) {
    return (
      <FormField key={field.name} label={field.label}>
        <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 === "organization") {
    return (
      <FormField key={field.name} label={field.label}>
        <Select {...register(field.name)}>
          <option value="">انتخاب سازمان…</option>
          {lookups.organizations.map((o) => (
            <option key={String(o.id)} value={String(o.id)}>
              {String(o.name)} ({String(o.code)})
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  if (field.type === "hub") {
    return (
      <FormField key={field.name} label={field.label}>
        <Select {...register(field.name)}>
          <option value="">انتخاب هاب…</option>
          {lookups.hubs.map((h) => (
            <option key={String(h.id)} value={String(h.id)}>
              {String(h.name)} ({String(h.code)})
            </option>
          ))}
        </Select>
      </FormField>
    );
  }
  return (
    <FormField key={field.name} label={field.label}>
      <Input {...register(field.name)} placeholder={field.placeholder} />
    </FormField>
  );
}

export function createCommunicationListPage(config: CommunicationListConfig) {
  return function CommunicationListPage() {
    const { tenantId } = useTenantId();
    const qc = useQueryClient();
    const perms = useCommunicationPermissions();
    const lookupsQ = useCommunicationLookups(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 pageSize = 20;

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

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

    const listQ = useQuery({
      queryKey: ["communication", tenantId, config.resourceKey, page],
      queryFn: async () => normalizeList(await config.api.list(tenantId!, { page, page_size: pageSize })),
      enabled: !!tenantId,
    });

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

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

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

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

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

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

    const rows = listQ.data ?? [];
    const lookups = { organizations: [] as Record<string, unknown>[], hubs: [] as Record<string, unknown>[] };
    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 (
      <>
        <CommunicationTablePage
          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>
          }
        />

        <CommunicationStatGrid
          stats={[
            { label: "کل", value: String(rows.length) },
            {
              label: "فعال",
              value: String(rows.filter((r) => r.status === "active").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)}
        />

        {/* Row action buttons rendered via table extension - inline actions in footer */}
        {rows.length > 0 && (canEdit || canDelete || config.rowActions) ? (
          <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, 5).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, 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}
                      {config.rowActions?.map((a) => (
                        <Button
                          key={a.label}
                          variant={a.variant ?? "outline"}
                          size="sm"
                          onClick={() => a.onClick(tenantId, row)}
                        >
                          {a.label}
                        </Button>
                      ))}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : null}
      </>
    );
  };
}
