"use client";

import { useEffect, useState } from "react";
import Link from "next/link";
import { AppShell } from "@/components/AppShell";
import {
  addService,
  archiveProperty,
  getProperty,
  propertyDocumentDownloadUrl,
  removePropertyDocument,
  removeService,
  removeTrust,
  restoreProperty,
  updateService,
  uploadPropertyDocument,
  upsertTrust,
} from "@/lib/api";
import { useCan } from "@/lib/abilities";
import { ChildCollection, type ChildConfig } from "@/components/ChildCollection";
import {
  expiryPhrase,
  formatDate,
  formatMoney,
  formatNumber,
  SERVICE_KIND_LABELS,
  serviceKindGlyph,
  serviceKindLabel,
  serviceNoteLabel,
  SIN_NOMBRE,
  trustStatusLabel,
} from "@/lib/labels";
import type { PropertyDetail, Service, Transaction, TrustInput } from "@/lib/types";

export default function PropiedadDetailPage({
  params,
}: {
  params: { id: string };
}) {
  // Next 14 passes `params` as a plain object here — no `use()` unwrapping.
  const { id } = params;
  return (
    <AppShell>
      <Detail id={id} />
    </AppShell>
  );
}

function Detail({ id }: { id: string }) {
  const [data, setData] = useState<PropertyDetail | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let alive = true;
    setLoading(true);
    setError(null);
    getProperty(id)
      .then((d) => {
        if (alive) {
          setData(d);
          setLoading(false);
        }
      })
      .catch((e) => {
        if (alive) {
          setError(
            e?.status === 404
              ? "No encontramos esta propiedad."
              : e?.message ?? "No se pudo cargar la propiedad.",
          );
          setLoading(false);
        }
      });
    return () => {
      alive = false;
    };
  }, [id]);

  if (loading) return <DetailSkeleton />;

  if (error)
    return (
      <>
        <BackLink />
        <div className="state-error" role="alert">
          {error}
        </div>
      </>
    );

  if (!data) return null;

  const reload = () => getProperty(id).then(setData).catch(() => {});

  return (
    <div className="rise">
      <div className="detail-actionbar">
        <BackLink />
        <PropertyActions data={data} onChange={reload} />
      </div>
      <Hero data={data} />
      <ClienteSection data={data} />
      <ServiciosSection data={data} />
      <FideicomisoSection data={data} />
      {data.policy && <PolizaSection data={data} />}
      <MovimientosSection data={data} />
      <DocumentosSection data={data} />
      <PropertyEditor data={data} onChange={reload} />
    </div>
  );
}

/** Edit / archive controls for the property header. */
function PropertyActions({
  data,
  onChange,
}: {
  data: PropertyDetail;
  onChange: () => void;
}) {
  const canEdit = useCan("property:update");
  const canDelete = useCan("property:delete");
  const [busy, setBusy] = useState(false);
  const archived = data.archivedAt != null;

  async function toggle() {
    const verb = archived ? "restaurar" : "archivar";
    if (!window.confirm(`¿Seguro que desea ${verb} esta propiedad?`)) return;
    setBusy(true);
    try {
      if (archived) await restoreProperty(data.id);
      else await archiveProperty(data.id);
      onChange();
    } catch (e) {
      window.alert((e as Error)?.message ?? "No se pudo completar la acción.");
    } finally {
      setBusy(false);
    }
  }

  if (!canEdit && !canDelete) return null;
  return (
    <div className="row-actions">
      {archived && <span className="badge badge-negative">Archivada</span>}
      {canEdit && (
        <Link href={`/servicios/${data.id}/editar`} className="btn btn-outline">
          Editar
        </Link>
      )}
      {canDelete && (
        <button type="button" className="btn btn-ghost" onClick={toggle} disabled={busy}>
          {archived ? "Restaurar" : "Archivar"}
        </button>
      )}
    </div>
  );
}

/** Editable services + trust + documents — only for users who can edit. */
function PropertyEditor({
  data,
  onChange,
}: {
  data: PropertyDetail;
  onChange: () => void;
}) {
  const canEdit = useCan("property:update");
  if (!canEdit) return null;

  const SERVICES: ChildConfig = {
    apiKind: "services",
    title: "Servicios",
    fields: [
      {
        key: "kind",
        label: "Tipo",
        type: "select",
        options: Object.entries(SERVICE_KIND_LABELS).map(([value, label]) => ({
          value,
          label,
        })),
      },
      { key: "accountNumber", label: "Cuenta" },
      { key: "meterNumber", label: "Medidor" },
      { key: "route", label: "Ruta" },
      { key: "dueDay", label: "Día pago" },
      { key: "notes", label: "Notas" },
      { key: "active", label: "Activo", type: "checkbox" },
    ],
  };

  return (
    <section className="section">
      <div className="section-head">
        <span className="section-rule cuenta" aria-hidden />
        <h2 className="section-title">Administrar propiedad</h2>
      </div>

      <ChildCollection
        config={SERVICES}
        rows={data.services as unknown as Record<string, unknown>[]}
        canEdit={canEdit}
        onAdd={async (p) => { await addService(data.id, p as never); onChange(); }}
        onSave={async (sid, p) => { await updateService(data.id, sid, p as never); onChange(); }}
        onRemove={async (sid) => { await removeService(data.id, sid); onChange(); }}
      />

      <TrustEditor data={data} onChange={onChange} />

      <DocumentsEditor data={data} onChange={onChange} />
    </section>
  );
}

/** Upload / download / delete document blobs stored in object storage (MinIO). */
function DocumentsEditor({
  data,
  onChange,
}: {
  data: PropertyDetail;
  onChange: () => void;
}) {
  const [file, setFile] = useState<File | null>(null);
  const [type, setType] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function upload() {
    if (!file) return;
    setBusy(true);
    setError(null);
    try {
      await uploadPropertyDocument(data.id, file, type.trim() || undefined);
      setFile(null);
      setType("");
      onChange();
    } catch (e) {
      setError((e as Error)?.message ?? "No se pudo subir el archivo.");
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="card" style={{ padding: 16 }}>
      <h3 className="section-title" style={{ marginTop: 0 }}>Documentos</h3>
      {data.documents.length > 0 && (
        <div className="tx-scroll">
          <table className="tx-table">
            <thead>
              <tr><th>Tipo</th><th>Clave</th><th className="num">Acción</th></tr>
            </thead>
            <tbody>
              {data.documents.map((d) => (
                <tr key={d.id ?? d.storageKey}>
                  <td>{d.documentType ?? "—"}</td>
                  <td className="mono">{d.storageKey ?? "—"}</td>
                  <td>
                    <div className="row-actions">
                      {d.id && (
                        <a
                          className="btn btn-ghost"
                          href={propertyDocumentDownloadUrl(data.id, d.id)}
                        >
                          Descargar
                        </a>
                      )}
                      <button
                        type="button"
                        className="btn btn-ghost"
                        onClick={async () => {
                          if (!d.id) return;
                          if (!window.confirm("¿Eliminar este documento?")) return;
                          try {
                            await removePropertyDocument(data.id, d.id);
                            onChange();
                          } catch (e) {
                            window.alert((e as Error)?.message ?? "No se pudo eliminar.");
                          }
                        }}
                      >
                        Eliminar
                      </button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
      {error && <div className="state-box state-error" style={{ marginTop: 12 }}>{error}</div>}
      <div className="inline-form" style={{ marginTop: 12 }}>
        <input
          className="input"
          placeholder="Tipo (ej. RECIBO)"
          value={type}
          onChange={(e) => setType(e.target.value)}
        />
        <input
          type="file"
          className="input"
          onChange={(e) => setFile(e.target.files?.[0] ?? null)}
        />
        <button
          type="button"
          className="btn btn-primary"
          disabled={!file || busy}
          onClick={upload}
        >
          {busy ? "Subiendo…" : "Subir"}
        </button>
      </div>
    </div>
  );
}

/** Trust is 1:1 — a small inline form that upserts or clears it. */
function TrustEditor({
  data,
  onChange,
}: {
  data: PropertyDetail;
  onChange: () => void;
}) {
  const t = data.trustAccount;
  const [bankName, setBankName] = useState(t?.bankName ?? "");
  const [trustNumber, setTrustNumber] = useState(t?.trustNumber ?? "");
  const [bankFee, setBankFee] = useState(t?.bankFee != null ? String(t.bankFee) : "");
  const [dueDate1, setDueDate1] = useState(toDateInput(t?.dueDate1));
  const [dueDate2, setDueDate2] = useState(toDateInput(t?.dueDate2));
  const [busy, setBusy] = useState(false);

  async function save() {
    setBusy(true);
    const input: TrustInput = {
      bankName: bankName.trim() || undefined,
      trustNumber: trustNumber.trim() || undefined,
      bankFee: bankFee.trim() === "" ? undefined : Number(bankFee),
      dueDate1: dueDate1 || undefined,
      dueDate2: dueDate2 || undefined,
    };
    try {
      await upsertTrust(data.id, input);
      onChange();
    } catch (e) {
      window.alert((e as Error)?.message ?? "No se pudo guardar el fideicomiso.");
    } finally {
      setBusy(false);
    }
  }

  async function clear() {
    if (!window.confirm("¿Eliminar el fideicomiso de esta propiedad?")) return;
    try {
      await removeTrust(data.id);
      onChange();
    } catch (e) {
      window.alert((e as Error)?.message ?? "No se pudo eliminar.");
    }
  }

  return (
    <div className="card" style={{ padding: 16, marginBottom: 14 }}>
      <h3 className="section-title" style={{ marginTop: 0 }}>Fideicomiso</h3>
      <div className="form-grid">
        <label className="field">
          <span className="field-label">Banco</span>
          <input className="input" value={bankName} onChange={(e) => setBankName(e.target.value)} />
        </label>
        <label className="field">
          <span className="field-label">No. fideicomiso</span>
          <input className="input" value={trustNumber} onChange={(e) => setTrustNumber(e.target.value)} />
        </label>
        <label className="field">
          <span className="field-label">Cuota banco</span>
          <input className="input" type="number" step="0.01" value={bankFee} onChange={(e) => setBankFee(e.target.value)} />
        </label>
        <label className="field">
          <span className="field-label">Vence 1</span>
          <input className="input" type="date" value={dueDate1} onChange={(e) => setDueDate1(e.target.value)} />
        </label>
        <label className="field">
          <span className="field-label">Vence 2 (próxima)</span>
          <input className="input" type="date" value={dueDate2} onChange={(e) => setDueDate2(e.target.value)} />
        </label>
      </div>
      <div className="form-actions">
        <button type="button" className="btn btn-primary" onClick={save} disabled={busy}>
          {busy ? "Guardando…" : t ? "Guardar fideicomiso" : "Crear fideicomiso"}
        </button>
        {t && (
          <button type="button" className="btn btn-ghost" onClick={clear}>
            Eliminar
          </button>
        )}
      </div>
    </div>
  );
}

function toDateInput(v: string | null | undefined): string {
  if (!v) return "";
  const d = new Date(v);
  return isNaN(d.getTime()) ? "" : d.toISOString().slice(0, 10);
}

function BackLink() {
  return (
    <Link href="/servicios" className="back-link">
      ← Volver a Propiedades
    </Link>
  );
}

/* ------------------------------------------------------------------ Hero */
function Hero({ data }: { data: PropertyDetail }) {
  const addr = [data.addressLine1, data.addressLine2].filter(Boolean).join(", ");
  const phones = [data.phone1, data.phone2, data.phone3].filter(Boolean);
  const provenance = [data.legacySourceTable, data.legacyId]
    .filter(Boolean)
    .join(" #");
  const activos = data.services.filter((s) => s.active).length;
  const phrase = expiryPhrase(data.daysToTrustDue);

  const facts: { label: string; value: string }[] = [
    { label: "Cliente", value: data.customer.name },
    {
      label: "Servicios",
      value:
        data.services.length === 0
          ? "Ninguno"
          : `${activos} activos de ${data.services.length}`,
    },
    { label: "Municipio", value: data.municipality || "—" },
    {
      label: "Fideicomiso",
      value: data.trustAccount
        ? formatDate(data.trustAccount.dueDate2)
        : "Sin fideicomiso",
    },
    { label: "Teléfonos", value: phones.join(" · ") || "—" },
  ];

  return (
    <div className="detail-hero">
      <div className="hero-top">
        <div>
          <h1 className="hero-name">{addr || "Propiedad sin dirección"}</h1>
          <div className="hero-provenance">
            {data.zone ? `Zona ${data.zone} · ` : ""}
            {data.customer.name}
          </div>
          {provenance && (
            <div className="hero-provenance">Origen: {provenance}</div>
          )}
        </div>
        <div className="hero-badges">
          {data.municipality && (
            <span className="badge badge-servicios">
              <span className="dot" /> {data.municipality}
            </span>
          )}
          {data.trustAccount ? (
            <span className={`badge status-${data.trustStatus}`}>
              Fideicomiso · {trustStatusLabel(data.trustStatus)}
              {phrase && data.trustStatus !== "expired" ? ` · ${phrase}` : ""}
            </span>
          ) : (
            <span className="badge badge-on-dark">Sin fideicomiso</span>
          )}
          {data.services.length === 0 && (
            <span className="badge badge-neutral">Sin servicios</span>
          )}
        </div>
      </div>
      <div className="hero-facts">
        {facts.map((f) => (
          <div key={f.label}>
            <div className="hero-fact-label">{f.label}</div>
            <div className="hero-fact-value">{f.value}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* -------------------------------------------------------------- Cliente */
function ClienteSection({ data }: { data: PropertyDetail }) {
  const c = data.customer;
  const location = [c.city?.replace(/,\s*$/, ""), c.state]
    .filter(Boolean)
    .join(", ");

  return (
    <section className="section">
      <SectionHead rule="datos" title="Cliente" />
      <div className="card">
        <Link href={`/clientes/${c.id}`} className="owner-link">
          <div>
            <div
              className={`owner-name${
                c.name === SIN_NOMBRE ? " cust-name-missing" : ""
              }`}
            >
              {c.name}
            </div>
            <div className="cust-sub">
              {location && <span>{location}</span>}
              {location && (c.phone || c.mobile || c.email) && (
                <span className="sep">·</span>
              )}
              {(c.phone || c.mobile) && <span>{c.phone || c.mobile}</span>}
              {c.email && (
                <>
                  <span className="sep">·</span>
                  <span>{c.email}</span>
                </>
              )}
              {c._count.policies > 0 && (
                <>
                  <span className="sep">·</span>
                  <span>
                    {c._count.policies}{" "}
                    {c._count.policies === 1 ? "póliza" : "pólizas"}
                  </span>
                </>
              )}
            </div>
          </div>
          <span className="owner-cta">Ver expediente →</span>
        </Link>

        {data.siblings.length > 0 && (
          <div className="linked-props">
            <div className="kv-label">
              Otras propiedades de este cliente ({data.siblings.length})
            </div>
            {data.siblings.map((s) => (
              <Link key={s.id} href={`/servicios/${s.id}`} className="linked-prop link">
                {[s.addressLine1, s.addressLine2].filter(Boolean).join(", ") ||
                  "Propiedad"}
                <span className="muted">
                  {s.zone ? ` · Zona ${s.zone}` : ""} · {s.serviceCount}{" "}
                  {s.serviceCount === 1 ? "servicio" : "servicios"}
                </span>
              </Link>
            ))}
          </div>
        )}
      </div>
    </section>
  );
}

/* ------------------------------------------------------------- Servicios */
function ServiciosSection({ data }: { data: PropertyDetail }) {
  return (
    <section className="section">
      <SectionHead
        rule="servicios"
        title="Servicios"
        count={data.services.length}
      />
      <div className="card">
        {data.services.length === 0 ? (
          <div className="empty-inline">
            Esta propiedad no tiene servicios registrados.
          </div>
        ) : (
          <div className="svc-grid" style={{ padding: 16 }}>
            {data.services.map((s) => (
              <ServiceCard key={s.id} s={s} />
            ))}
          </div>
        )}
      </div>
    </section>
  );
}

function ServiceCard({ s }: { s: Service }) {
  const noteLabel = serviceNoteLabel(s.kind);
  return (
    <div className={`svc-item${s.active ? "" : " inactive"}`}>
      <div className="svc-head">
        <span className="svc-kind">
          <span className="svc-glyph" aria-hidden>
            {serviceKindGlyph(s.kind)}
          </span>
          {serviceKindLabel(s.kind)}
        </span>
        {!s.active && <span className="badge badge-neutral">Inactivo</span>}
      </div>
      <div className="svc-detail">
        {s.accountNumber && (
          <span>
            Cuenta: <span className="mono">{s.accountNumber}</span>
          </span>
        )}
        {s.meterNumber && (
          <span>
            Medidor: <span className="mono">{s.meterNumber}</span>
          </span>
        )}
        {s.route && (
          <span>
            Ruta: <span className="mono">{s.route}</span>
          </span>
        )}
        {s.dueDay && <span>Día de pago: {s.dueDay}</span>}
        {s.notes && (
          <span>
            {noteLabel ? `${noteLabel}: ` : ""}
            {s.notes}
          </span>
        )}
      </div>
    </div>
  );
}

/* ---------------------------------------------------------- Fideicomiso */
function FideicomisoSection({ data }: { data: PropertyDetail }) {
  const t = data.trustAccount;
  const phrase = expiryPhrase(data.daysToTrustDue);

  return (
    <section className="section">
      <SectionHead rule="cuenta" title="Fideicomiso" />
      <div className="card">
        {!t ? (
          <div className="empty-inline">
            Esta propiedad no tiene fideicomiso registrado.
          </div>
        ) : (
          <>
            <div className="kv-grid">
              <KV label="Banco" value={t.bankName} />
              <KV label="Número de fideicomiso" value={t.trustNumber} />
              <KV
                label="Comisión anual"
                value={formatMoney(t.bankFee, "MXN")}
              />
              <KV label="Vigencia desde" value={formatDate(t.dueDate1)} />
              <KV
                label="Próximo vencimiento"
                value={
                  t.dueDate2
                    ? `${formatDate(t.dueDate2)}${phrase ? ` · ${phrase}` : ""}`
                    : null
                }
              />
              <KV
                label="Estado"
                value={trustStatusLabel(data.trustStatus)}
              />
            </div>
            <div className="section-note" style={{ padding: "0 22px 18px" }}>
              La comisión bancaria se cobra cada año en el próximo
              vencimiento; el sistema anterior guardaba el par de fechas
              (vence1 / vence2) del periodo en curso y del siguiente.
            </div>
          </>
        )}
      </div>
    </section>
  );
}

/* --------------------------------------------------------------- Póliza */
function PolizaSection({ data }: { data: PropertyDetail }) {
  const p = data.policy!;
  return (
    <section className="section">
      <SectionHead rule="seguros" title="Póliza vinculada" />
      <div className="card">
        <Link href={`/polizas/${p.id}`} className="owner-link">
          <div>
            <div className="owner-name mono">{p.policyNumber || "—"}</div>
            <div className="cust-sub">
              {p.policyType?.name && <span>{p.policyType.name}</span>}
              {p.policyTo && (
                <>
                  <span className="sep">·</span>
                  <span>Vence {formatDate(p.policyTo)}</span>
                </>
              )}
            </div>
          </div>
          <span className="owner-cta">Ver póliza →</span>
        </Link>
      </div>
    </section>
  );
}

/* ---------------------------------------------------------- Movimientos */
function MovimientosSection({ data }: { data: PropertyDetail }) {
  return (
    <section className="section">
      <SectionHead
        rule="cuenta"
        title="Movimientos de servicios"
        count={data.customerTransactions.length}
        countSuffix="recientes"
      />

      {data.customerLedger.length > 0 && (
        <div className="summary-grid">
          {data.customerLedger.map((row) => (
            <div className="summary-card UTILITY" key={row.currency}>
              <div className="summary-domain">
                <span className="tx-dot UTILITY" />
                Servicios · {row.currency}
              </div>
              <div className="summary-total">
                {formatMoney(row.total, row.currency)}
              </div>
              <div className="summary-count">
                {formatNumber(row.count)}{" "}
                {row.count === 1 ? "movimiento" : "movimientos"}
              </div>
            </div>
          ))}
        </div>
      )}

      <div className="card">
        {data.customerTransactions.length === 0 ? (
          <div className="empty-inline">Sin movimientos de servicios.</div>
        ) : (
          <div className="tx-scroll">
            <table className="tx-table">
              <thead>
                <tr>
                  <th>Fecha</th>
                  <th>Tipo</th>
                  <th>Periodo</th>
                  <th>Referencia</th>
                  <th className="num">Monto</th>
                </tr>
              </thead>
              <tbody>
                {data.customerTransactions.map((t) => (
                  <TxRow key={t.id} t={t} />
                ))}
              </tbody>
            </table>
          </div>
        )}
        <div className="section-note" style={{ padding: "0 16px 14px" }}>
          Los movimientos pertenecen al cliente, no a esta propiedad: el
          sistema anterior nunca ligó un pago a una propiedad concreta. Ver el{" "}
          <Link
            href={`/estado-cuenta/${data.customerId}`}
            className="inline-link"
          >
            estado de cuenta completo
          </Link>
          .
        </div>
      </div>
    </section>
  );
}

function TxRow({ t }: { t: Transaction }) {
  const num = t.amount != null ? Number(t.amount) : NaN;
  const sign = !Number.isNaN(num) && num < 0 ? "neg" : "pos";
  return (
    <tr>
      <td className="mono" style={{ whiteSpace: "nowrap" }}>
        {formatDate(t.transactionDate)}
      </td>
      <td>{t.type?.nameEs || t.type?.nameEn || "—"}</td>
      <td>{t.period || "—"}</td>
      <td className="tx-ref">{t.reference || "—"}</td>
      <td className="num">
        <span className={`tx-amount ${sign}`}>
          {formatMoney(t.amount, t.currency)}
        </span>{" "}
        <span className="tx-cur">{t.currency}</span>
      </td>
    </tr>
  );
}

/* ----------------------------------------------------------- Documentos */
function DocumentosSection({ data }: { data: PropertyDetail }) {
  return (
    <section className="section">
      <SectionHead rule="docs" title="Documentos" count={data.documents.length} />
      <div className="card">
        {data.documents.length === 0 ? (
          <div className="empty-inline">
            No hay documentos registrados para esta propiedad.
          </div>
        ) : (
          <>
            <div className="doc-list">
              {data.documents.map((d, i) => (
                <div className="doc-item" key={d.id ?? i}>
                  <span className="doc-icon" aria-hidden>
                    ▤
                  </span>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div className="doc-type">{d.documentType || "Documento"}</div>
                    <div className="doc-key">{d.storageKey || "—"}</div>
                  </div>
                  {d.id && (
                    <a
                      className="btn btn-ghost"
                      href={propertyDocumentDownloadUrl(data.id, d.id)}
                    >
                      Descargar
                    </a>
                  )}
                </div>
              ))}
            </div>
          </>
        )}
      </div>
    </section>
  );
}

/* ------------------------------------------------------------ helpers */
function KV({
  label,
  value,
}: {
  label: string;
  value: string | null | undefined;
}) {
  return (
    <div>
      <div className="kv-label">{label}</div>
      <div className="kv-value">{value || "—"}</div>
    </div>
  );
}

function SectionHead({
  rule,
  title,
  count,
  countSuffix,
}: {
  rule: string;
  title: string;
  count?: number;
  countSuffix?: string;
}) {
  return (
    <div className="section-head">
      <span className={`section-rule ${rule}`} aria-hidden />
      <h2 className="section-title">{title}</h2>
      {count != null && (
        <span className="section-count">
          {count} {countSuffix ?? ""}
        </span>
      )}
    </div>
  );
}

function DetailSkeleton() {
  return (
    <div>
      <div
        className="skeleton"
        style={{ height: 16, width: 160, marginBottom: 18 }}
      />
      <div className="skeleton" style={{ height: 180, borderRadius: 16 }} />
      <div
        className="skeleton"
        style={{ height: 160, borderRadius: 16, marginTop: 34 }}
      />
      <div
        className="skeleton"
        style={{ height: 240, borderRadius: 16, marginTop: 34 }}
      />
    </div>
  );
}
