// -----------------------------------------------------------------------------
// Lou-Ka — Agrégateur de logements à louer (province de Québec)
// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
// pages/Listing.tsx : fiche d'un logement — refonte mobile-first
//   Ordre mobile : galerie → prix + badge marché → chips clés → ancres →
//   description restructurée → inclusions → détails pratiques → quartier →
//   à proximité → pied de fiche. CTA source sticky en bas d'écran (mobile).
//   Desktop : deux colonnes (logement à gauche, quartier/synthèse à droite)
//   via wrappers `display:contents` + `order` (voir styles.css « fiche v2 »).
// -----------------------------------------------------------------------------
import { useEffect, useRef, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { Listing, fetchListing, fetchSources, fmtAvailability, fmtDist, fmtPrice, registerSourceNames, sourceName } from "../api";
import QuartierBlock from "../components/QuartierBlock";

// Icônes et libellés des commodités de proximité (louka/poi.py)
const POI_META: Record<string, { icon: string; label: string }> = {
  epicerie: { icon: "🛒", label: "Épicerie" },
  depanneur: { icon: "🏪", label: "Dépanneur" },
  pharmacie: { icon: "💊", label: "Pharmacie" },
  ecole: { icon: "🏫", label: "École" },
  garderie: { icon: "🧸", label: "Garderie" },
  parc: { icon: "🌳", label: "Parc" },
  bus: { icon: "🚌", label: "Bus" },
  metro: { icon: "🚇", label: "Métro" },
  gym: { icon: "🏋️", label: "Gym" },
  cafe: { icon: "☕", label: "Café" },
  clinique: { icon: "🩺", label: "Clinique" },
  hopital: { icon: "🏥", label: "Hôpital" },
  bibliotheque: { icon: "📚", label: "Bibliothèque" },
};

// Regroupement des POI en catégories repliables
const POI_GROUPES: { titre: string; icone: string; cats: string[] }[] = [
  { titre: "Courses", icone: "🛒", cats: ["epicerie", "depanneur"] },
  { titre: "Transport", icone: "🚌", cats: ["bus", "metro"] },
  { titre: "Études et famille", icone: "🎓", cats: ["ecole", "garderie", "bibliotheque"] },
  { titre: "Santé", icone: "🏥", cats: ["pharmacie", "clinique", "hopital"] },
  { titre: "Vie de quartier", icone: "☕", cats: ["cafe", "parc", "gym"] },
];

// Badge « prix vs marché » — seuils configurables
const SEUILS_MARCHE = { bonDeal: -0.15, dansLeMarche: 0.10 };

const PETS_LABEL: Record<string, string> = {
  oui: "Animaux acceptés", non: "Animaux refusés", conditions: "Animaux sous conditions",
};

const NBSP = " ";

/** ≈ minutes de marche (vol d'oiseau × facteur de détour 1,3, 4,8 km/h) */
const fmtMarche = (m: number): string =>
  `≈${NBSP}${Math.max(1, Math.round((m * 1.3) / 80))}${NBSP}min à pied`;

function badgeMarche(price: number | null | undefined,
                     loyerSecteur: number | null | undefined) {
  if (price == null || loyerSecteur == null || loyerSecteur <= 0) return null;
  const delta = (price - loyerSecteur) / loyerSecteur;
  const pct = `${delta > 0 ? "+" : "−"}${Math.abs(Math.round(delta * 100))}${NBSP}%`;
  if (delta <= SEUILS_MARCHE.bonDeal)
    return { cls: "deal-good", txt: `${pct} vs le secteur · Bon deal 🔥` };
  if (delta <= SEUILS_MARCHE.dansLeMarche)
    return { cls: "deal-ok", txt: `${pct} vs le secteur · Dans le marché` };
  return { cls: "deal-high", txt: `${pct} vs le secteur · Au-dessus du marché` };
}

/** Badges dérivés des détails structurés (inclusions confirmées ✓). */
function badgesConfirmes(l: Listing): string[] {
  const d = l.details ?? {};
  const out: string[] = [];
  const inc = d.inclusions ?? {};
  if (inc.heating) out.push("Chauffage inclus");
  if (inc.electricity) out.push("Électricité incluse");
  if (inc.hot_water) out.push("Eau chaude incluse");
  if (inc.internet) out.push("Internet inclus");
  const app = d.appliances ?? {};
  if (app.dishwasher) out.push("Lave-vaisselle");
  if (app.washer_dryer) out.push("Laveuse-sécheuse");
  if (app.fridge && app.stove) out.push("Électroménagers");
  if (d.ac) out.push("Climatisation");
  if (d.elevator) out.push("Ascenseur");
  if (d.balcony) out.push("Balcon");
  if (d.pool) out.push("Piscine");
  if (d.gym) out.push("Gym");
  if (d.laundry) out.push("Buanderie");
  if (d.storage) out.push("Rangement");
  if (d.parking?.available)
    out.push(`Stationnement${d.parking.type ? ` ${d.parking.type}` : ""}${d.parking.included ? " inclus" : ""}`);
  if (l.furnished) out.push("Meublé");
  if (d.smoking === false) out.push("Non-fumeur");
  return out;
}

// --- Galerie avec balayage natif (scroll-snap) + compteur + plein écran -----
function Galerie({ images, titre }: { images: string[]; titre: string }) {
  const [idx, setIdx] = useState(0);
  const [zoom, setZoom] = useState(false);
  const track = useRef<HTMLDivElement>(null);

  const onScroll = () => {
    const el = track.current;
    if (el) setIdx(Math.round(el.scrollLeft / el.clientWidth));
  };
  const goto = (i: number) =>
    track.current?.scrollTo({ left: i * track.current.clientWidth, behavior: "smooth" });

  if (images.length === 0)
    return <div className="carousel"><div className="noimg carousel-empty">🏠</div></div>;

  return (
    <>
      <div className="carousel">
        <div className="carousel-track" ref={track} onScroll={onScroll}>
          {images.map((u, i) => (
            <img
              key={u} src={u} loading={i === 0 ? "eager" : "lazy"}
              alt={`${titre} — photo ${i + 1} de ${images.length}`}
              onClick={() => setZoom(true)}
            />
          ))}
        </div>
        <span className="carousel-count" aria-live="polite">{idx + 1}/{images.length}</span>
        {idx > 0 && (
          <button className="carousel-nav prev" aria-label="Photo précédente" onClick={() => goto(idx - 1)}>‹</button>
        )}
        {idx < images.length - 1 && (
          <button className="carousel-nav next" aria-label="Photo suivante" onClick={() => goto(idx + 1)}>›</button>
        )}
      </div>
      {images.length > 1 && (
        <div className="thumbs">
          {images.map((u, i) => (
            <button key={u} className={i === idx ? "on" : ""} onClick={() => goto(i)}
                    aria-label={`Photo ${i + 1}`}>
              <img src={u} alt="" loading="lazy" />
            </button>
          ))}
        </div>
      )}
      {zoom && (
        <div className="lightbox" onClick={() => setZoom(false)} role="dialog" aria-label="Photo agrandie">
          <img src={images[idx]} alt="" />
        </div>
      )}
    </>
  );
}

export default function ListingPage() {
  const { uid } = useParams<{ uid: string }>();
  const [l, setL] = useState<Listing | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetchSources().then((r) => registerSourceNames(r.sources)).catch(() => {});
    if (!uid) return;
    fetchListing(uid).then(setL).catch((e) => setError(String(e)));
    window.scrollTo(0, 0);
  }, [uid]);

  if (error)
    return (
      <div className="notice container">
        <div className="big">⚠️</div>
        <h2>Annonce introuvable</h2>
        <p>{error}</p>
        <Link className="btn btn-primary" to="/">Retour aux logements</Link>
      </div>
    );

  if (!l)
    return (
      <div className="container detail">
        <div className="fiche" aria-busy="true">
          <div className="skel"><div className="sk-img" /></div>
          <div className="skel"><div className="sk-line" /><div className="sk-line" /><div className="sk-line short" /></div>
        </div>
      </div>
    );

  const dg = l.digest ?? null;
  const f = dg?.faits;
  const conf = dg?.confiance ?? {};
  const deal = badgeMarche(l.price, l.quartier?.demographie?.loyer_moyen);
  const confirmes = badgesConfirmes(l);
  const autres = l.amenities.filter(
    (a) => !confirmes.some((b) => b.toLowerCase().includes(a.toLowerCase())));
  const inc = l.details?.inclusions ?? {};
  const zeroFrais = inc.heating && inc.electricity && inc.hot_water;

  const enLigneDepuis = l.first_seen
    ? Math.max(0, Math.round((Date.now() / 1000 - l.first_seen) / 86400)) : null;
  const hist = (l.price_history ?? []).filter((h) => h.price != null);
  const baissePrix = hist.length >= 2 && hist[0].price !== hist[1].price
    ? { de: hist[1].price!, a: hist[0].price! } : null;

  const updated = l.updated_at
    ? new Date(l.updated_at * 1000).toLocaleDateString("fr-CA", {
        day: "numeric", month: "long", year: "numeric" }) : null;

  // chips clés (haute confiance seulement pour les faits extraits du texte)
  const chips: string[] = [];
  if (l.unit_type) chips.push(l.unit_type);
  const dispo = fmtAvailability(l.availability_date);
  if (dispo) chips.push(dispo === "Maintenant" ? "Libre maintenant" : `Dispo ${dispo}`);
  if (l.furnished) chips.push("Meublé");
  if (l.pets) chips.push(PETS_LABEL[l.pets] ?? l.pets);
  if (l.area_sqft) chips.push(`${Math.round(l.area_sqft).toLocaleString("fr-CA")}${NBSP}pi²`);
  if (f?.nb_occupants_total && conf.nb_occupants_total !== "faible")
    chips.push(`${f.nb_occupants_total} occupants`);
  if (f?.salle_de_bain && conf.salle_de_bain !== "faible")
    chips.push(`Salle de bain ${f.salle_de_bain === "commune" ? "partagée" : "privée"}`);
  if (l.details?.floor != null) chips.push(`${l.details.floor}ᵉ étage`);

  const pois = l.poi ?? [];

  return (
    <div className="container detail">
      <nav className="crumbs" aria-label="Fil d'Ariane">
        <Link to="/">Logements</Link> ›
        {l.city && <span>{l.city}</span>} ›
        <span>{l.title || l.address}</span>
      </nav>

      <div className="fiche">
        {/* ------- colonne gauche (desktop) : galerie, description, pratique -- */}
        <div className="f-col">
          <section className="f-bloc f-galerie" aria-label="Photos">
            <Galerie images={l.images ?? []} titre={l.title || l.address} />
          </section>

          <section className="f-bloc f-desc" id="description">
            <h2>Description</h2>
            {dg ? (
              <>
                {dg.en_bref && <p className="enbref">{dg.en_bref}</p>}
                {dg.sections.map((s) => (
                  <div key={s.titre} className="desc-section">
                    <h4>{s.titre}</h4>
                    <p>{s.texte}</p>
                  </div>
                ))}
                <details className="texte-original">
                  <summary>Voir le texte original de la source</summary>
                  <p>{l.description}</p>
                </details>
              </>
            ) : (
              l.description
                ? <p style={{ color: "var(--ink-2)" }}>{l.description}</p>
                : <p className="fine">La source ne fournit pas de description pour cette annonce.</p>
            )}
          </section>

          <section className="f-bloc f-pratique">
            <h2>Détails pratiques</h2>
            <div className="kv">
              <div className="cell"><div className="k">Gestionnaire</div><div className="v">{sourceName(l.source)}</div></div>
              {l.price_label && (
                <div className="cell"><div className="k">Prix affiché</div><div className="v">{l.price_label}</div></div>
              )}
              {f?.duree_bail_minimale_mois && (
                <div className="cell"><div className="k">Bail minimum</div><div className="v">{f.duree_bail_minimale_mois} mois</div></div>
              )}
              {enLigneDepuis != null && (
                <div className="cell"><div className="k">En ligne depuis</div>
                  <div className="v">{enLigneDepuis === 0 ? "aujourd'hui" : `${enLigneDepuis}${NBSP}jour${enLigneDepuis > 1 ? "s" : ""}`}</div></div>
              )}
              {updated && (
                <div className="cell"><div className="k">Synchronisé</div><div className="v">{updated}</div></div>
              )}
            </div>
            {baissePrix && (
              <div className={`prix-histo ${baissePrix.a < baissePrix.de ? "down" : "up"}`}>
                {baissePrix.a < baissePrix.de ? "📉" : "📈"} Prix passé de{" "}
                {fmtPrice(baissePrix.de)} à <b>{fmtPrice(baissePrix.a)}</b>
                {baissePrix.a < baissePrix.de && " — levier de négociation"}
              </div>
            )}
          </section>
        </div>

        {/* ------- colonne droite (desktop) : synthèse, inclusions, quartier -- */}
        <div className="f-col">
          <section className="f-bloc f-hero">
            <div className="price">
              {fmtPrice(l.price, l.price_label)} {l.price != null && <small>/{NBSP}mois</small>}
            </div>
            {deal && <div className={`deal-badge ${deal.cls}`}>{deal.txt}</div>}
            <h1>{l.title || l.address}</h1>
            <div className="loc">
              {[l.address !== l.title ? l.address : "", l.sector, l.city].filter(Boolean).join(" · ")}
            </div>
            <div className="chips-scroll" role="list" aria-label="Caractéristiques clés">
              {chips.map((c) => <span className="chip-key" role="listitem" key={c}>{c}</span>)}
            </div>
            <nav className="ancres" aria-label="Sections de la fiche">
              <a href="#description">Description</a>
              <a href="#inclusions">Inclusions</a>
              <a href="#quartier">Quartier</a>
              <a href="#proximite">À proximité</a>
            </nav>
            <a className="cta cta-desktop" href={`/passerelle/${encodeURIComponent(l.uid)}`}
               target="_blank" rel="noopener noreferrer">
              Voir l'annonce chez {sourceName(l.source)} ↗
            </a>
            <a className="btn btn-ghost btn-pdf"
               href={`/api/listings/${encodeURIComponent(l.uid)}/pdf`} download>
              📄 Télécharger la fiche (PDF)
            </a>
          </section>

          <section className="f-bloc f-incl" id="inclusions">
            <h2>Inclusions et commodités</h2>
            {zeroFrais && <div className="deal-badge deal-good">💡 Chauffage, électricité et eau chaude inclus — 0{NBSP}$ de frais cachés</div>}
            <div className="amenity-row">
              {confirmes.map((b) => (
                <span className="amenity confirmed" key={`c-${b}`}>✓ {b}</span>
              ))}
              {autres.map((a) => (
                <span className="amenity unconfirmed" key={a} title="Mentionné par la source, sans confirmation structurée">{a}</span>
              ))}
            </div>
            {confirmes.length === 0 && autres.length === 0 && (
              <p className="fine">La source ne précise pas les inclusions.</p>
            )}
          </section>

          <section className="f-bloc f-quartier" id="quartier">
            {l.quartier ? <QuartierBlock q={l.quartier} /> : null}
          </section>

          <section className="f-bloc f-poi" id="proximite">
            {pois.length > 0 && (
              <>
                <h2>À proximité</h2>
                {POI_GROUPES.map((g, gi) => {
                  const items = pois.filter((p) => g.cats.includes(p.cat));
                  if (items.length === 0) return null;
                  return (
                    <details className="poi-groupe" key={g.titre} open={gi === 0}>
                      <summary>
                        <span>{g.icone} {g.titre}</span>
                        <span className="poi-resume">
                          {items.length} · le + proche à {fmtDist(items[0].dist_m)}
                        </span>
                      </summary>
                      <ul className="poi-list">
                        {items.map((p) => {
                          const meta = POI_META[p.cat] ?? { icon: "📍", label: p.cat };
                          return (
                            <li key={p.cat} title={meta.label}>
                              <span className="poi-ico" aria-hidden="true">{meta.icon}</span>
                              <span className="poi-name">{p.name}</span>
                              <span className="poi-dist">{fmtDist(p.dist_m)} · {fmtMarche(p.dist_m)}</span>
                            </li>
                          );
                        })}
                      </ul>
                    </details>
                  );
                })}
                <div className="fine">
                  Temps de marche estimés (distance à vol d'oiseau ×{NBSP}1,3, 4,8{NBSP}km/h) — données OpenStreetMap.
                </div>
              </>
            )}
          </section>
        </div>
      </div>

      <div className="fine f-foot">
        {updated && <>Dernière synchronisation : {updated}. </>}
        Les prix et disponibilités sont ceux affichés par la source — chaque fiche
        renvoie à l'annonce originale.
      </div>

      {/* CTA sticky mobile — toujours visible */}
      <div className="cta-sticky">
        <span className="cta-sticky-prix">{fmtPrice(l.price, l.price_label)}{l.price != null && <small>/mois</small>}</span>
        <a className="cta" href={`/passerelle/${encodeURIComponent(l.uid)}`}
           target="_blank" rel="noopener noreferrer">
          Voir chez {sourceName(l.source)} ↗
        </a>
      </div>
    </div>
  );
}
