"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { AdminPageHeader, Banner, Button, EmptyState, Modal } from "@/components/admin/controls";
import { useMe } from "@/hooks/useMe";
import type { CommercialAdminResourceDef } from "../admin/resources";
import {
  createAdminRegistryItem,
  deleteAdminRegistryItem,
  listAdminRegistry,
  type RegistryRecord,
  updateAdminRegistryItem,
} from "../adapters/admin";
import type { AdapterResult } from "../types";
import {
  COMMERCIAL_FIELD_GROUPS,
  FIELD_ENUM_OPTIONS,
  commercialDescription,
  commercialEntityName,
  enumLabel,
  fieldLabel,
  formatDate,
  friendlyMessage,
  isTechnicalField,
  registryKindForField,
} from "../presentation";

const PAGE_SIZE = 10;
function recordLabel(item: RegistryRecord, resource: CommercialAdminResourceDef): string {
  const name = item[resource.nameField];
  return commercialEntityName(
    resource.key,
    item[resource.codeField],
    typeof name === "string" ? name : null
  );
}

function recordCode(item: RegistryRecord, resource: CommercialAdminResourceDef): string {
  const code = item[resource.codeField];
  return code == null ? "" : String(code);
}

function recordTargetId(item: RegistryRecord, resource: CommercialAdminResourceDef): string {
  const target = item.registry_object_id ?? item.id ?? item[resource.codeField];
  return target == null ? "" : String(target);
}

const DEFAULT_RECORD_VALUES: Partial<
  Record<CommercialAdminResourceDef["key"], RegistryRecord>
> = {
  products: { visibility: "public", display_order: 0 },
  "trial-rules": { duration_days: 14, grace_period_days: 3, auto_disable: true },
  pricing: { pricing_model: "monthly", currency: "IRR", amount_minor: 0 },
  policies: {
    effect: "deny",
    parameters: {
      custom_domain_allowed: false,
      subdomain_only: true,
      ssl_ready: false,
    },
  },
};

function defaultRecord(resource: CommercialAdminResourceDef): RegistryRecord {
  const seed: RegistryRecord = {
    [resource.codeField]: "",
    [resource.nameField]: "",
    status: "draft",
  };
  Object.assign(seed, DEFAULT_RECORD_VALUES[resource.key] || {});
  return seed;
}

function parseFieldValue(key: string, input: string, current: unknown): unknown {
  if (Array.isArray(current) || /(_refs|_codes|capabilities)$/.test(key)) {
    return input.split("،").flatMap((part) => part.split(",")).map((part) => part.trim()).filter(Boolean);
  }
  if (typeof current === "number" || /(amount|days|order|percent|limit)$/.test(key)) {
    return input === "" ? null : Number(input);
  }
  return input;
}

function FieldInput({
  name,
  value,
  onChange,
  resourceKind,
  entityCode,
  presentAsName = false,
}: {
  name: string;
  value: unknown;
  onChange: (value: unknown) => void;
  resourceKind: string;
  entityCode?: unknown;
  presentAsName?: boolean;
}) {
  if (Array.isArray(value)) {
    return (
      <div className="sm:col-span-2">
        <p className="text-sm font-medium text-secondary">{fieldLabel(name)}</p>
        <div className="mt-2 flex flex-wrap gap-2">
          {value.length ? value.map((item, index) => (
            <span key={`${String(item)}-${index}`} className="rounded-full bg-sky-50 px-3 py-1 text-xs text-sky-800">
              {commercialEntityName(registryKindForField(name) || resourceKind, item)}
            </span>
          )) : <span className="text-xs text-gray-500">موردی انتخاب نشده است.</span>}
        </div>
      </div>
    );
  }
  if (typeof value === "boolean") {
    return (
      <label className="flex cursor-pointer items-center justify-between rounded-xl border border-gray-200 px-4 py-3">
        <span className="text-sm font-medium text-secondary">{fieldLabel(name)}</span>
        <input type="checkbox" checked={value} onChange={(event) => onChange(event.target.checked)} className="h-4 w-4 accent-primary" />
      </label>
    );
  }
  if (value && typeof value === "object" && !Array.isArray(value)) {
    return (
      <fieldset className="rounded-2xl border border-gray-200 p-4">
        <legend className="px-2 text-sm font-semibold text-secondary">{fieldLabel(name)}</legend>
        <div className="grid gap-4 sm:grid-cols-2">
          {Object.entries(value as Record<string, unknown>)
            .filter(([key]) => !isTechnicalField(key))
            .map(([key, nested]) => (
              <FieldInput
                key={key}
                name={key}
                value={nested}
                resourceKind={resourceKind}
                onChange={(next) => onChange({ ...(value as Record<string, unknown>), [key]: next })}
              />
            ))}
        </div>
      </fieldset>
    );
  }
  const rawValue = value == null ? "" : String(value);
  const displayValue = !rawValue
    ? ""
    : presentAsName
      ? commercialEntityName(resourceKind, entityCode, rawValue)
      : name === "description"
        ? commercialDescription(resourceKind, rawValue)
        : rawValue;
  if (FIELD_ENUM_OPTIONS[name]) {
    return (
      <label className="block">
        <span className="text-sm font-medium text-secondary">{fieldLabel(name)}</span>
        <select value={displayValue} onChange={(event) => onChange(event.target.value)} className="mt-1 w-full rounded-xl border border-gray-200 bg-white px-3 py-2.5 text-sm">
          {FIELD_ENUM_OPTIONS[name].map((option) => <option key={option} value={option}>{enumLabel(option)}</option>)}
        </select>
      </label>
    );
  }
  return (
    <label className={name === "description" ? "block sm:col-span-2" : "block"}>
      <span className="text-sm font-medium text-secondary">{fieldLabel(name)}</span>
      {name === "description" ? (
        <textarea value={displayValue} onChange={(event) => onChange(event.target.value)} rows={3} className="mt-1 w-full rounded-xl border border-gray-200 px-3 py-2.5 text-sm" />
      ) : (
        <input
          type={typeof value === "number" ? "number" : /(_at|date)$/.test(name) ? "date" : "text"}
          value={displayValue}
          onChange={(event) => onChange(parseFieldValue(name, event.target.value, value))}
          placeholder={Array.isArray(value) ? "موارد را با ویرگول جدا کنید" : undefined}
          className="mt-1 w-full rounded-xl border border-gray-200 px-3 py-2.5 text-sm"
        />
      )}
    </label>
  );
}

function CommercialRecordForm({
  value,
  resource,
  onChange,
}: {
  value: RegistryRecord;
  resource: CommercialAdminResourceDef;
  onChange: (record: RegistryRecord) => void;
}) {
  const visibleKeys = Object.keys(value).filter((key) => !isTechnicalField(key));
  const grouped = new Set<string>(COMMERCIAL_FIELD_GROUPS.flatMap((group) => [...group.keys]));
  const advanced = visibleKeys.filter((key) => !grouped.has(key) && key !== resource.nameField);
  const setField = (key: string, next: unknown) => onChange({ ...value, [key]: next });

  return (
    <div className="max-h-[65vh] space-y-6 overflow-y-auto px-1">
      {COMMERCIAL_FIELD_GROUPS.map((group) => {
        const keys = Array.from(new Set([
          ...(group.title === "اطلاعات پایه" ? [resource.nameField] : []),
          ...group.keys,
        ])).filter((key) => key in value && !isTechnicalField(key));
        if (!keys.length) return null;
        return (
          <section key={group.title} className="rounded-2xl bg-gray-50 p-4">
            <h3 className="mb-4 text-sm font-bold text-secondary">{group.title}</h3>
            <div className="grid gap-4 sm:grid-cols-2">
              {keys.map((key) => <FieldInput key={key} name={key} value={value[key]} resourceKind={resource.key} entityCode={value[resource.codeField]} presentAsName={key === resource.nameField} onChange={(next) => setField(key, next)} />)}
            </div>
          </section>
        );
      })}
      {advanced.length ? (
        <details className="rounded-2xl border border-gray-200 p-4">
          <summary className="cursor-pointer text-sm font-bold text-secondary">تنظیمات پیشرفته</summary>
          <p className="mt-2 text-xs text-gray-500">این بخش برای تنظیمات کم‌استفاده است. تغییر آن‌ها ممکن است روی انتشار اثر بگذارد.</p>
          <div className="mt-4 grid gap-4 sm:grid-cols-2">
            {advanced.map((key) => <FieldInput key={key} name={key} value={value[key]} resourceKind={resource.key} entityCode={value[resource.codeField]} presentAsName={key === resource.nameField} onChange={(next) => setField(key, next)} />)}
          </div>
        </details>
      ) : null}
    </div>
  );
}

export function AdminRegistryManager({ resource }: { resource: CommercialAdminResourceDef }) {
  const { me } = useMe();
  const [result, setResult] = useState<AdapterResult<RegistryRecord[]> | null>(null);
  const [error, setError] = useState("");
  const [msg, setMsg] = useState("");
  const [loading, setLoading] = useState(true);
  const [createOpen, setCreateOpen] = useState(false);
  const [editItem, setEditItem] = useState<RegistryRecord | null>(null);
  const [formBody, setFormBody] = useState<RegistryRecord>({});
  const [busy, setBusy] = useState(false);
  const [query, setQuery] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");
  const [sortAsc, setSortAsc] = useState(true);
  const [page, setPage] = useState(1);
  const [selected, setSelected] = useState<Set<string>>(new Set());

  const load = useCallback(async () => {
    setLoading(true);
    setError("");
    const response = await listAdminRegistry(resource, me?.current_tenant_id);
    setResult(response);
    if (["unavailable", "permission_denied", "error"].includes(response.availability)) {
      setError(friendlyMessage(response.message, "بارگذاری اطلاعات انجام نشد. لطفاً دوباره تلاش کنید."));
    }
    setLoading(false);
  }, [me?.current_tenant_id, resource]);

  useEffect(() => { void load(); }, [load]);

  const items = useMemo(() => result?.data ?? [], [result]);
  const filtered = useMemo(() => {
    const normalized = query.trim().toLocaleLowerCase("fa");
    return items
      .filter((item) => statusFilter === "all" || item.status === statusFilter)
      .filter((item) => !normalized || recordLabel(item, resource).toLocaleLowerCase("fa").includes(normalized))
      .sort((a, b) => recordLabel(a, resource).localeCompare(recordLabel(b, resource), "fa") * (sortAsc ? 1 : -1));
  }, [items, query, resource, sortAsc, statusFilter]);
  const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const visible = filtered.slice((Math.min(page, pages) - 1) * PAGE_SIZE, Math.min(page, pages) * PAGE_SIZE);

  const openCreate = () => {
    setFormBody(defaultRecord(resource));
    setCreateOpen(true);
    setMsg("");
    setError("");
  };
  const openEdit = (item: RegistryRecord) => {
    setEditItem(item);
    setFormBody({ ...item });
    setMsg("");
    setError("");
  };

  const submitCreate = async (event: FormEvent) => {
    event.preventDefault();
    setBusy(true);
    setError("");
    const body = { ...formBody };
    if (!body[resource.codeField]) {
      body[resource.codeField] = `${resource.key.replace(/s$/, "")}.${Date.now().toString(36)}`;
    }
    const response = await createAdminRegistryItem(resource, body);
    if (!response.ok) setError(friendlyMessage(response.message, "ثبت اطلاعات انجام نشد. لطفاً فیلدهای ضروری را بررسی کنید."));
    else {
      setCreateOpen(false);
      setMsg("اطلاعات با موفقیت ثبت شد.");
      await load();
    }
    setBusy(false);
  };

  const submitEdit = async (event: FormEvent) => {
    event.preventDefault();
    if (!editItem) return;
    const targetId = recordTargetId(editItem, resource);
    if (!targetId) return setError("شناسه این مورد پیدا نشد. صفحه را تازه‌سازی کنید.");
    const changedFields = Object.fromEntries(
      Object.entries(formBody).filter(
        ([key, value]) =>
          ![
            "registry_object_id",
            "id",
            "kind",
            "slug",
            "stable_code",
            "created_at",
            "updated_at",
            "created_by",
            "updated_by",
            "published_at",
            "archived_at",
            "is_deleted",
            "clone_of_id",
          ].includes(key) && !Object.is(value, editItem[key])
      )
    );
    if (!Object.keys(changedFields).length) {
      setEditItem(null);
      setMsg("تغییری برای ذخیره وجود نداشت.");
      return;
    }
    setBusy(true);
    const response = await updateAdminRegistryItem(resource, targetId, changedFields);
    if (!response.ok) setError(friendlyMessage(response.message, "ذخیره تغییرات انجام نشد. دوباره تلاش کنید."));
    else {
      setEditItem(null);
      setMsg("تغییرات با موفقیت ذخیره شد.");
      await load();
    }
    setBusy(false);
  };

  const removeItems = async (targets: RegistryRecord[]) => {
    const confirmation =
      targets.length === 1
        ? resource.presentation.deleteConfirmation
        : `آیا از حذف ${targets.length.toLocaleString("fa-IR")} مورد از ${resource.presentation.pluralLabel} مطمئن هستید؟`;
    if (!targets.length || !window.confirm(confirmation)) return;
    setBusy(true);
    for (const item of targets) {
      const targetId = recordTargetId(item, resource);
      if (targetId) {
        const response = await deleteAdminRegistryItem(resource, targetId);
        if (!response.ok) {
          setError(friendlyMessage(response.message, "حذف بعضی موارد انجام نشد."));
          break;
        }
      }
    }
    setSelected(new Set());
    await load();
    setBusy(false);
  };

  return (
    <div className="space-y-6">
      <AdminPageHeader
        title={resource.presentation.sectionTitle}
        subtitle={resource.presentation.description}
        action={<div className="flex flex-wrap gap-2"><Link href="/admin/commercial"><Button variant="outline">بازگشت</Button></Link>{!resource.readOnly ? <Button onClick={openCreate}>{resource.presentation.createButtonText}</Button> : null}</div>}
      />
      {error ? <Banner variant="error">{error}</Banner> : null}
      {msg ? <Banner variant="success">{msg}</Banner> : null}

      <div className="flex flex-wrap items-center gap-3 rounded-2xl border border-gray-100 bg-white p-4 shadow-sm">
        <label className="relative min-w-[220px] flex-1">
          <span className="sr-only">جست‌وجو</span>
          <span className="pointer-events-none absolute right-3 top-2.5" aria-hidden="true">⌕</span>
          <input value={query} onChange={(event) => { setQuery(event.target.value); setPage(1); }} placeholder={`جست‌وجو در ${resource.presentation.pluralLabel}`} className="w-full rounded-xl border border-gray-200 py-2.5 pl-4 pr-10 text-sm" />
        </label>
        <select value={statusFilter} onChange={(event) => { setStatusFilter(event.target.value); setPage(1); }} aria-label="فیلتر وضعیت" className="rounded-xl border border-gray-200 bg-white px-3 py-2.5 text-sm">
          <option value="all">همه وضعیت‌ها</option><option value="active">فعال</option><option value="published">منتشرشده</option><option value="draft">پیش‌نویس</option><option value="inactive">غیرفعال</option>
        </select>
        <Button variant="outline" size="sm" onClick={() => setSortAsc((value) => !value)}>مرتب‌سازی {sortAsc ? "الف تا ی" : "ی تا الف"}</Button>
        {selected.size && !resource.readOnly ? <Button variant="outline" size="sm" disabled={busy} onClick={() => void removeItems(items.filter((item) => selected.has(recordCode(item, resource))))}>حذف انتخاب‌شده‌ها</Button> : null}
      </div>

      <section className="overflow-hidden rounded-2xl border border-gray-100 bg-white shadow-sm">
        {loading ? (
          <div className="space-y-3 p-5" aria-label="در حال بارگذاری">{[1, 2, 3].map((i) => <div key={i} className="h-12 animate-pulse rounded-xl bg-gray-100" />)}</div>
        ) : !visible.length ? (
          <EmptyState message={query || statusFilter !== "all" ? `نتیجه‌ای در ${resource.presentation.pluralLabel} پیدا نشد.` : resource.presentation.emptyStateTitle} />
        ) : (
          <div className="overflow-x-auto">
            <table className="w-full min-w-[680px] text-sm">
              <thead className="bg-gray-50 text-right">
                <tr>
                  {!resource.readOnly ? <th className="w-12 px-4 py-3"><span className="sr-only">انتخاب</span></th> : null}
                  {resource.presentation.columns.map((column) => <th key={column.key} className="px-4 py-3 font-semibold text-secondary">{column.label}</th>)}
                  <th className="px-4 py-3 font-semibold text-secondary">عملیات</th>
                </tr>
              </thead>
              <tbody>
                {visible.map((item, index) => {
                  const code = recordCode(item, resource) || `row-${index}`;
                  const status = typeof item.status === "string" ? item.status : "inactive";
                  return (
                    <tr key={code} className="border-t border-gray-100 hover:bg-gray-50/60">
                      {!resource.readOnly ? <td className="px-4 py-3"><input type="checkbox" checked={selected.has(code)} aria-label={`انتخاب ${recordLabel(item, resource)}`} onChange={() => setSelected((current) => { const next = new Set(current); next.has(code) ? next.delete(code) : next.add(code); return next; })} /></td> : null}
                      {resource.presentation.columns.map((column) => {
                        if (column.key === "name") return <td key={column.key} className="px-4 py-3 font-medium text-secondary">{recordLabel(item, resource)}</td>;
                        if (column.key === "status") return <td key={column.key} className="px-4 py-3"><span className={`rounded-full px-2.5 py-1 text-xs ${status === "active" || status === "published" ? "bg-emerald-50 text-emerald-700" : status === "draft" ? "bg-amber-50 text-amber-700" : "bg-gray-100 text-gray-600"}`}>{resource.presentation.statusMap[status] || enumLabel(status)}</span></td>;
                        if (column.key === "version") return <td key={column.key} className="px-4 py-3 text-gray-600">{item.version || item.version_code ? `نسخه ${String(item.version || item.version_code)}` : "—"}</td>;
                        if (column.key === "updated_at") return <td key={column.key} className="px-4 py-3 text-gray-600">{formatDate(typeof item.updated_at === "string" ? item.updated_at : null)}</td>;
                        return <td key={column.key} className="px-4 py-3 text-gray-600">{enumLabel(item.visibility)}</td>;
                      })}
                      <td className="px-4 py-3">
                        {resource.readOnly ? (
                          <span className="text-xs text-gray-500">نمایش فقط‌خواندنی</span>
                        ) : (
                          <div className="flex gap-2"><Button variant="outline" size="sm" onClick={() => openEdit(item)}><span aria-hidden="true">✎</span> ویرایش</Button><Button variant="outline" size="sm" disabled={busy} onClick={() => void removeItems([item])}><span aria-hidden="true">♲</span> حذف</Button></div>
                        )}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
        {filtered.length > PAGE_SIZE ? (
          <div className="flex items-center justify-between border-t border-gray-100 px-4 py-3 text-xs text-gray-500">
            <Button size="sm" variant="outline" disabled={page <= 1} onClick={() => setPage((value) => value - 1)}>قبلی</Button>
            <span>صفحه {Math.min(page, pages).toLocaleString("fa-IR")} از {pages.toLocaleString("fa-IR")}</span>
            <Button size="sm" variant="outline" disabled={page >= pages} onClick={() => setPage((value) => value + 1)}>بعدی</Button>
          </div>
        ) : null}
      </section>

      <Modal open={createOpen} onClose={() => setCreateOpen(false)} title={resource.presentation.createButtonText}>
        <form onSubmit={(event) => void submitCreate(event)} className="space-y-5">
          <CommercialRecordForm value={formBody} resource={resource} onChange={setFormBody} />
          <div className="flex justify-end gap-2"><Button type="button" variant="outline" onClick={() => setCreateOpen(false)}>انصراف</Button><Button type="submit" loading={busy}>ثبت و ذخیره</Button></div>
        </form>
      </Modal>
      <Modal open={Boolean(editItem)} onClose={() => setEditItem(null)} title={resource.presentation.editDialogTitle}>
        <form onSubmit={(event) => void submitEdit(event)} className="space-y-5">
          <CommercialRecordForm value={formBody} resource={resource} onChange={setFormBody} />
          <div className="flex justify-end gap-2"><Button type="button" variant="outline" onClick={() => setEditItem(null)}>انصراف</Button><Button type="submit" loading={busy}>ذخیره تغییرات</Button></div>
        </form>
      </Modal>
    </div>
  );
}
