const { useState, useEffect, useRef, useCallback } = React;

// ── helpers ──────────────────────────────────────────────────────────────────

function fmt(n) {
  if (n == null) return "—";
  return Number(n).toLocaleString("es-AR");
}

// ── ListingCard ───────────────────────────────────────────────────────────────

function ListingCard({ listing, onSimilar }) {
  return (
    <div style={{
      background: "#fff", borderRadius: 8, overflow: "hidden",
      boxShadow: "0 1px 3px rgba(0,0,0,.1)", display: "flex", flexDirection: "column",
    }}>
      {listing.image_url
        ? <img src={listing.image_url} alt={listing.title}
            style={{ width: "100%", height: 160, objectFit: "cover" }} />
        : <div style={{ width: "100%", height: 160, background: "#eee",
            display: "flex", alignItems: "center", justifyContent: "center",
            color: "#aaa", fontSize: ".8rem" }}>Sin foto</div>
      }
      <div style={{ padding: "0.75rem", flex: 1, display: "flex", flexDirection: "column", gap: 4 }}>
        <div style={{ fontWeight: 600, fontSize: ".9rem" }}>
          {listing.link
            ? <a href={listing.link} target="_blank" rel="noreferrer"
                style={{ color: "#1a1a2e", textDecoration: "none" }}>
                {listing.title || "Ver propiedad"}
              </a>
            : listing.title || "—"}
        </div>
        <div style={{ fontSize: ".8rem", color: "#666" }}>
          {listing.barrio || ""}
          {listing.propiedad && (
            <span style={{ marginLeft: 6, background: "#e8eaf6", color: "#3949ab",
              borderRadius: 4, padding: "1px 6px", fontSize: ".75rem" }}>
              {listing.propiedad}
            </span>
          )}
        </div>
        <div style={{ fontSize: ".95rem", fontWeight: 500, marginTop: "auto" }}>
          USD {fmt(listing.price)}
          {(listing.surface || listing.m2c) && (
            <span style={{ fontSize: ".8rem", color: "#888", fontWeight: 400 }}>
              {" · "}{listing.surface || listing.m2c} m²
            </span>
          )}
        </div>
        {listing.id && (
          <button onClick={() => onSimilar(listing)}
            style={{ marginTop: 8, padding: "6px 0", background: "#f5f5f5",
              border: "1px solid #ddd", borderRadius: 6, cursor: "pointer",
              fontSize: ".82rem", color: "#333" }}>
            Ver similares
          </button>
        )}
      </div>
    </div>
  );
}

function ListingGrid({ listings, onSimilar, emptyMsg = "Sin resultados." }) {
  if (!listings.length) return <p style={{ color: "#888", fontSize: ".85rem", marginTop: "1rem" }}>{emptyMsg}</p>;
  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
      gap: "1rem", marginTop: "1rem",
    }}>
      {listings.map((l, i) => <ListingCard key={l.id ?? i} listing={l} onSimilar={onSimilar} />)}
    </div>
  );
}

// ── PriceChart ────────────────────────────────────────────────────────────────

function PriceChart({ data }) {
  const ref = useRef(null);
  const chartRef = useRef(null);
  useEffect(() => {
    if (!data || !ref.current) return;
    if (chartRef.current) chartRef.current.destroy();
    chartRef.current = new Chart(ref.current, {
      type: "line",
      data: {
        labels: data.surfaces,
        datasets: [
          { label: "Mediana",  data: data.median,      borderColor: "#1a1a2e", tension: 0.3, pointRadius: 0 },
          { label: "md+std",   data: data.md_plus_std, borderColor: "#7986cb", borderDash: [4,4], tension: 0.3, pointRadius: 0 },
          { label: "md-std",   data: data.md_minus_std,borderColor: "#7986cb", borderDash: [4,4], tension: 0.3, pointRadius: 0 },
          { label: "Mín",      data: data.min,         borderColor: "#ccc",    borderDash: [2,4], tension: 0.3, pointRadius: 0 },
          { label: "Máx",      data: data.max,         borderColor: "#ccc",    borderDash: [2,4], tension: 0.3, pointRadius: 0 },
        ],
      },
      options: {
        responsive: true,
        plugins: { legend: { position: "bottom" } },
        scales: {
          x: { title: { display: true, text: "m² cubiertos" } },
          y: { title: { display: true, text: "Precio USD" } },
        },
      },
    });
    return () => chartRef.current?.destroy();
  }, [data]);
  return <canvas ref={ref} style={{ maxHeight: 280 }} />;
}

// ── SimilarPortfolio ──────────────────────────────────────────────────────────

function SimilarPortfolio({ listing, onBack }) {
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError]     = useState(null);
  const [current, setCurrent] = useState(listing);

  const load = useCallback(async (l) => {
    setLoading(true); setError(null);
    try {
      const res = await fetch(`/similar/${l.id}?top_k=20`);
      if (!res.ok) throw new Error(`Error ${res.status}`);
      setResults(await res.json());
    } catch (e) { setError(e.message); }
    finally { setLoading(false); }
  }, []);

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

  const handleSimilar = (l) => { setCurrent(l); load(l); };

  return (
    <div>
      <div style={{ display: "flex", alignItems: "center", gap: "1rem", marginBottom: "1rem" }}>
        <button onClick={onBack} style={{ background: "none", border: "1px solid #ccc",
          borderRadius: 6, padding: "6px 12px", cursor: "pointer", fontSize: ".9rem" }}>
          ← Volver
        </button>
        <span style={{ fontSize: ".9rem", color: "#555" }}>
          Similares a: <strong>{current.title || current.id}</strong>
        </span>
      </div>
      {loading && <p style={{ color: "#888" }}>Buscando similares…</p>}
      {error   && <p style={{ color: "red", fontSize: ".85rem" }}>{error}</p>}
      {!loading && !error && (
        <ListingGrid listings={results} onSimilar={handleSimilar}
          emptyMsg="No se encontraron propiedades similares." />
      )}
    </div>
  );
}

// ── Constants ─────────────────────────────────────────────────────────────────

const BARRIOS = ["", "nuñez", "colegiales", "villa crespo", "villa urquiza", "san isidro", "paternal"];
const PROPIEDADES = [
  { value: "", label: "Tipo" },
  { value: "D", label: "Depto" },
  { value: "C", label: "Casa" },
  { value: "P", label: "PH" },
];

// ── Main search panel ─────────────────────────────────────────────────────────

function SearchPanel({ onSimilar }) {
  const [query,   setQuery]   = useState("");
  const [filters, setFilters] = useState({
    barrio: "", propiedad: "",
    min_price: "", max_price: "",
    min_m2c: "", max_m2c: "",
    min_antiguedad: "", max_antiguedad: "",
  });
  const [results,   setResults]   = useState([]);
  const [chartData, setChartData] = useState(null);
  const [total,     setTotal]     = useState(null);
  const [loading,   setLoading]   = useState(false);
  const [error,     setError]     = useState(null);

  const setFilter = (k) => (e) => setFilters(f => ({ ...f, [k]: e.target.value }));

  const numericFilters = () => {
    const n = {};
    ["min_price","max_price","min_m2c","max_m2c","min_antiguedad","max_antiguedad"].forEach(k => {
      if (filters[k] !== "") n[k] = Number(filters[k]);
    });
    if (filters.barrio)    n.barrio    = filters.barrio;
    if (filters.propiedad) n.propiedad = filters.propiedad;
    return n;
  };

  const handleSearch = useCallback(async () => {
    setLoading(true); setError(null); setChartData(null);
    try {
      if (query.trim()) {
        // NLP search — filters applied server-side
        const payload = { query, top_k: 20, ...numericFilters() };
        const res = await fetch("/search", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
        if (!res.ok) throw new Error(`Error ${res.status}`);
        const results = await res.json();
        setResults(results);
        setTotal(results.length);
      } else {
        // No query — use filter endpoint (also shows chart)
        const body = new URLSearchParams();
        Object.entries(filters).forEach(([k, v]) => v !== "" && body.append(k, v));
        const res = await fetch("/filter_json", { method: "POST", body });
        if (!res.ok) throw new Error(`Error ${res.status}`);
        const data = await res.json();
        setChartData(data);
        setResults(data.matches || []);
        setTotal(data.total_matches);
      }
    } catch (e) { setError(e.message); }
    finally { setLoading(false); }
  }, [query, filters]);

  const onKey = (e) => e.key === "Enter" && handleSearch();

  return (
    <div>
      {/* Search bar + filters row */}
      <div className="card">
        <div style={{ display: "flex", gap: ".6rem", flexWrap: "wrap", alignItems: "flex-end" }}>
          {/* NLP search box */}
          <div style={{ flex: "2 1 280px" }}>
            <label style={{ display: "block", fontSize: ".78rem", color: "#666", marginBottom: ".25rem" }}>
              Búsqueda
            </label>
            <input
              value={query}
              onChange={e => setQuery(e.target.value)}
              onKeyDown={onKey}
              placeholder="Ej: departamento luminoso en palermo 3 ambientes con balcón"
            />
          </div>

          {/* Barrio */}
          <div className="field" style={{ flex: "1 1 130px" }}>
            <label>Barrio</label>
            <select value={filters.barrio} onChange={setFilter("barrio")}>
              {BARRIOS.map(b => <option key={b} value={b}>{b || "Todos"}</option>)}
            </select>
          </div>

          {/* Tipo */}
          <div className="field" style={{ flex: "0 1 90px" }}>
            <label>Tipo</label>
            <select value={filters.propiedad} onChange={setFilter("propiedad")}>
              {PROPIEDADES.map(p => <option key={p.value} value={p.value}>{p.label}</option>)}
            </select>
          </div>

          {/* Price range */}
          <div className="field" style={{ flex: "1 1 100px" }}>
            <label>Precio mín USD</label>
            <input type="number" value={filters.min_price} onChange={setFilter("min_price")} placeholder="0" />
          </div>
          <div className="field" style={{ flex: "1 1 100px" }}>
            <label>Precio máx USD</label>
            <input type="number" value={filters.max_price} onChange={setFilter("max_price")} placeholder="∞" />
          </div>

          {/* Surface range */}
          <div className="field" style={{ flex: "0 1 80px" }}>
            <label>m² mín</label>
            <input type="number" value={filters.min_m2c} onChange={setFilter("min_m2c")} placeholder="0" />
          </div>
          <div className="field" style={{ flex: "0 1 80px" }}>
            <label>m² máx</label>
            <input type="number" value={filters.max_m2c} onChange={setFilter("max_m2c")} placeholder="∞" />
          </div>

          {/* Search button */}
          <div style={{ flex: "0 0 auto", paddingBottom: "1px" }}>
            <button onClick={handleSearch} disabled={loading} style={{ whiteSpace: "nowrap" }}>
              {loading ? "Buscando…" : "Buscar"}
            </button>
          </div>
        </div>

        {error && <p style={{ color: "red", fontSize: ".85rem", marginTop: ".5rem" }}>{error}</p>}
        {total != null && (
          <p style={{ color: "#888", fontSize: ".82rem", marginTop: ".5rem" }}>
            {total} resultado{total !== 1 ? "s" : ""}
            {query.trim() ? " · filtros aplicados sobre búsqueda semántica" : ""}
          </p>
        )}
      </div>

      {/* Chart (only shown when no NLP query) */}
      {chartData && (
        <div className="card" style={{ marginTop: 0 }}>
          <PriceChart data={chartData} />
        </div>
      )}

      {/* Results */}
      <ListingGrid listings={results} onSimilar={onSimilar} />
    </div>
  );
}

// ── App ───────────────────────────────────────────────────────────────────────

function App() {
  const [view,           setView]           = useState("main");
  const [similarListing, setSimilarListing] = useState(null);

  const handleSimilar = (listing) => {
    setSimilarListing(listing);
    setView("similar");
    window.scrollTo(0, 0);
  };

  if (view === "similar" && similarListing) {
    return (
      <div style={{ padding: "1.5rem" }}>
        <SimilarPortfolio listing={similarListing} onBack={() => setView("main")} />
      </div>
    );
  }

  return <SearchPanel onSimilar={handleSimilar} />;
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
