"use client";

/**
 * ListingsCard — Секция 2 «Рынок» из mockup tradein.html.
 * Counts strip + filters + price bar + table.
 */
import { useMemo } from "react";
import type { AggregatedEstimate, AnalogLot, CianPriceChangeStats } from "@/types/trade-in";
import { safeUrl } from "@/lib/safeUrl";
import { useEstimateCianPriceChanges } from "@/lib/trade-in-api";
import { openRosreestrWithAddress } from "@/lib/rosreestr";
import { sourceDot, sourceLabel } from "@/lib/source-registry";

interface Props {
  estimate: AggregatedEstimate;
  estimateId?: string;
}

function fmtRub(v: number): string {
  return v.toLocaleString("ru-RU");
}

function fmtArea(v: number): string {
  return v.toFixed(1);
}

/** Гуманизация свежести данных (#770 finding #31): мин → ч → дн. */
function humanizeAgo(min: number | null): string {
  if (min === null || min < 0) return "—";
  if (min < 60) return `${min} мин назад`;
  if (min < 1440) return `${Math.round(min / 60)} ч назад`;
  return `${Math.round(min / 1440)} дн назад`;
}

/** Extract Cian numeric ID from a source_url like https://ekb.cian.ru/sale/flat/123456789/ */
function extractCianId(url: string | null): string | null {
  if (!url) return null;
  const m = url.match(/\/sale\/flat\/(\d+)/);
  return m ? m[1] : null;
}

export function ListingsCard({ estimate, estimateId }: Props) {
  const priceChangesQuery = useEstimateCianPriceChanges(estimateId ?? null);

  const priceChangeMap = useMemo<Map<string, CianPriceChangeStats>>(() => {
    const map = new Map<string, CianPriceChangeStats>();
    for (const stats of priceChangesQuery.data ?? []) {
      map.set(stats.cian_id, stats);
    }
    return map;
  }, [priceChangesQuery.data]);

  const lots = estimate.analogs;
  if (lots.length === 0) {
    return (
      <article className="card">
        <div className="card-head">
          <div>
            <div className="section-kicker">Секция 2 · Рынок</div>
            <h2>Объявления — аналогичные квартиры в продаже</h2>
          </div>
        </div>
        <div className="card-body">
          <p style={{ color: "var(--muted)", textAlign: "center", padding: "24px 0" }}>
            Нет объявлений-аналогов в радиусе 2 км.
          </p>
        </div>
      </article>
    );
  }

  // Считаем источники
  const sourceCounts: Record<string, number> = {};
  for (const l of lots) {
    if (l.source) sourceCounts[l.source] = (sourceCounts[l.source] ?? 0) + 1;
  }

  // Price bar bounds
  const prices = lots.map((l) => l.price_rub).sort((a, b) => a - b);
  const lo = prices[0];
  const hi = prices[prices.length - 1];
  const m = estimate.median_price_rub;
  const span = hi - lo;
  const medPct = span > 0 ? Math.max(5, Math.min(95, ((m - lo) / span) * 100)) : 50;
  const p25 = prices[Math.floor(prices.length * 0.25)];
  const p75 = prices[Math.floor(prices.length * 0.75)];
  const p25Pct = span > 0 ? Math.max(5, Math.min(95, ((p25 - lo) / span) * 100)) : 25;
  const p75Pct = span > 0 ? Math.max(5, Math.min(95, ((p75 - lo) / span) * 100)) : 75;

  // Площадь / годы / комнаты — для filter chips
  const areas = lots.map((l) => l.area_m2);
  const aMin = Math.min(...areas);
  const aMax = Math.max(...areas);
  const rooms = lots[0]?.rooms;

  return (
    <article className="card">
      <div className="card-head">
        <div>
          <div className="section-kicker">Секция 2 · Рынок</div>
          <h2>Объявления — аналогичные квартиры в продаже</h2>
        </div>
        <div className="card-meta">
          <div>
            Обновлено:{" "}
            <b className="mono">{humanizeAgo(estimate.data_freshness_minutes)}</b>
          </div>
          <div style={{ marginTop: 4 }}>
            {/* #2211: без знаменателя — sources_used включает и оценочные
                источники, любой фиксированный знаменатель либо врёт, либо
                оказывается меньше числителя (консистентно с HeroSummary). */}
            Источников: <b>{estimate.sources_used.length}</b>
          </div>
        </div>
      </div>

      <div className="count-strip">
        <div className="count-cell">
          <div className="label">Объявлений по аналогам</div>
          <div className="value">
            <span data-tnum>{estimate.n_analogs}</span>
            <span className="unit">шт</span>
          </div>
          <div className="sub">из {estimate.sources_used.length} источников</div>
        </div>
        <div className="count-cell">
          <div className="label">Медиана</div>
          <div className="value">
            {m > 0 ? (
              <>
                <span data-tnum>{(m / 1_000_000).toFixed(2)}</span>
                <span className="unit">млн ₽</span>
              </>
            ) : (
              <span data-tnum>—</span>
            )}
          </div>
          <div className="sub">
            {m > 0 ? `${estimate.median_price_per_m2.toLocaleString("ru-RU")} ₽/м²` : "нет данных"}
          </div>
        </div>
        <div className="count-cell">
          <div className="label">Диапазон P25–P75</div>
          <div className="value">
            <span data-tnum>
              {(estimate.range_low_rub / 1_000_000).toFixed(1)}–
              {(estimate.range_high_rub / 1_000_000).toFixed(1)}
            </span>
            <span className="unit">млн</span>
          </div>
          {/* #2211 находка 4: настоящий CV (σ/среднее ₽/м², #2043) когда бэкенд его
              отдал; иначе честный «разброс» = ширина диапазона (НЕ коэффициент
              вариации, поэтому без аббревиатуры CV). */}
          <div className="sub">
            {typeof estimate.cv === "number" && estimate.cv > 0 ? (
              <abbr title="Коэффициент вариации цен аналогов (σ/среднее ₽/м²)">CV</abbr>
            ) : (
              <abbr title="Ширина ценового диапазона относительно медианы (не коэффициент вариации)">
                разброс
              </abbr>
            )}{" "}
            {typeof estimate.cv === "number" && estimate.cv > 0
              ? `${(estimate.cv * 100).toFixed(1)}%`
              : m > 0
                ? `${(((estimate.range_high_rub - estimate.range_low_rub) / m) * 100).toFixed(1)}%`
                : "—"}
          </div>
        </div>
      </div>

      <div className="filters-row">
        <span className="lbl">Фильтр</span>
        <div className="filters">
          <span className="chip">
            <span className="k">Расстояние</span>
            <span className="v">≤ 2 км</span>
          </span>
          {rooms !== undefined && (
            <span className="chip">
              <span className="k">Планировка</span>
              <span className="v">{rooms === 0 ? "Студия" : `${rooms}-к`}</span>
            </span>
          )}
          <span className="chip">
            <span className="k">Площадь</span>
            <span className="v">
              {fmtArea(aMin)} – {fmtArea(aMax)} м²
            </span>
          </span>
        </div>
      </div>

      <div className="filters-row">
        <span className="lbl">Источники</span>
        <div className="sources">
          {Object.entries(sourceCounts).map(([src, count]) => (
            <span key={src} className="source-chip">
              <span className={`src-dot ${sourceDot(src)}`} /> {sourceLabel(src)} ·{" "}
              <span className="mono" style={{ color: "var(--muted)" }}>
                {count}
              </span>
            </span>
          ))}
        </div>
      </div>

      <div className="pricebar-block">
        <div className="bar-head">
          <span
            className="bar-title"
            style={{ color: "var(--fg-2)", fontSize: 12, letterSpacing: "0.04em" }}
          >
            ДИАПАЗОН ЦЕН В ОБЪЯВЛЕНИЯХ
            {m > 0 ? ` · ${(m / 1_000_000).toFixed(2)} МЛН ₽ медиана` : ""}
          </span>
        </div>
        <div className="pricebar">
          <div className="axis">
            <div className="range" style={{ left: "5%", right: "5%" }} />
            <div className="median" style={{ left: `${medPct}%` }} />
          </div>
          <div className="endpoint" style={{ left: "5%" }}>
            <div className="endpoint-val">{(lo / 1_000_000).toFixed(1)} млн</div>
            <div className="endpoint-tick" />
          </div>
          <div className="endpoint" style={{ left: `${p25Pct}%` }} title="P25">
            <div className="endpoint-val mono" style={{ fontWeight: 500, color: "var(--muted)" }}>
              {(p25 / 1_000_000).toFixed(1)}
            </div>
            <div className="endpoint-tick" />
          </div>
          <div className="endpoint" style={{ left: `${p75Pct}%` }} title="P75">
            <div className="endpoint-val mono" style={{ fontWeight: 500, color: "var(--muted)" }}>
              {(p75 / 1_000_000).toFixed(1)}
            </div>
            <div className="endpoint-tick" />
          </div>
          <div className="endpoint" style={{ left: "95%" }}>
            <div className="endpoint-val">{(hi / 1_000_000).toFixed(1)} млн</div>
            <div className="endpoint-tick" />
          </div>
          <div className="median-label" style={{ left: `${medPct}%`, top: -2 }}>
            {(m / 1_000_000).toFixed(2)} млн ₽
          </div>
          <div className="exp left">P25 · {(p25 / 1_000_000).toFixed(1)} МЛН</div>
          <div className="exp right">P75 · {(p75 / 1_000_000).toFixed(1)} МЛН</div>
        </div>
      </div>

      <table className="dt" aria-label="Аналогичные объявления">
        <thead>
          <tr>
            <th>Адрес</th>
            <th>Источник</th>
            <th className="num">₽ / м²</th>
            <th className="num">Стоимость</th>
            <th className="num">Дист.</th>
            <th><span className="sr-only">Действия</span></th>
          </tr>
        </thead>
        <tbody>
          {lots.map((lot, i) => (
            <AnalogRow
              key={`${lot.source ?? ""}|${lot.address}|${lot.price_rub}|${i}`}
              lot={lot}
              priceChangeMap={priceChangeMap}
            />
          ))}
        </tbody>
      </table>

      <div className="table-foot">
        <span>
          Показано <b style={{ color: "var(--fg)" }}>{lots.length}</b> из {estimate.n_analogs}{" "}
          объявлений · отсортировано по расстоянию
        </span>
      </div>
    </article>
  );
}

function AnalogRow({
  lot,
  priceChangeMap,
}: {
  lot: AnalogLot;
  priceChangeMap: Map<string, CianPriceChangeStats>;
}) {
  const src = lot.source ?? "";
  const dot = sourceDot(src);
  const label = sourceLabel(src);
  const distance =
    lot.distance_m === null
      ? "—"
      : lot.distance_m < 1000
        ? `${lot.distance_m} м`
        : `${(lot.distance_m / 1000).toFixed(1)} км`;
  const externalUrl = safeUrl(lot.source_url);

  const cianId = src === "cian" ? extractCianId(lot.source_url) : null;
  const priceStats = cianId ? priceChangeMap.get(cianId) : undefined;

  return (
    <tr>
      <td>
        <div className="addr">
          <span className="a-main">{lot.address}</span>
          <span className="a-sub">
            {fmtArea(lot.area_m2)} м² · {lot.rooms === 0 ? "студия" : `${lot.rooms}-к`}
            {lot.floor !== null && lot.total_floors !== null
              ? ` · этаж ${lot.floor}/${lot.total_floors}`
              : ""}
          </span>
        </div>
      </td>
      <td>
        <span className="src-mini">
          <span className={`src-dot ${dot}`} /> {label}
        </span>
      </td>
      <td className="num">
        {fmtRub(lot.price_per_m2)}
      </td>
      <td className="num">
        {fmtRub(lot.price_rub)}
        {priceStats && (
          <span
            style={{
              fontSize: 11,
              padding: "2px 6px",
              borderRadius: 4,
              background:
                priceStats.last_diff_percent != null && priceStats.last_diff_percent < 0
                  ? "#dcfce7"
                  : "#fee2e2",
              color:
                priceStats.last_diff_percent != null && priceStats.last_diff_percent < 0
                  ? "#166534"
                  : "#991b1b",
              marginLeft: 6,
            }}
          >
            {priceStats.n_changes > 1 ? `↓${priceStats.n_changes}` : "↓1"}
            {priceStats.last_diff_percent != null
              ? ` ${priceStats.last_diff_percent > 0 ? "+" : ""}${priceStats.last_diff_percent.toFixed(1)}%`
              : ""}
          </span>
        )}
      </td>
      <td className="num">{distance}</td>
      <td style={{ whiteSpace: "nowrap" }}>
        {externalUrl && (
          <a
            href={externalUrl}
            target="_blank"
            rel="noopener noreferrer"
            className="row-link"
            aria-label="Открыть оригинал"
          >
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
              <polyline points="15 3 21 3 21 9" />
              <line x1="10" y1="14" x2="21" y2="3" />
            </svg>
          </a>
        )}
        <button
          type="button"
          className="rosreestr-btn"
          onClick={() => void openRosreestrWithAddress(lot.address)}
          title="Скопировать адрес и открыть форму запроса выписки ЕГРН"
        >
          Росреестр ↗
        </button>
      </td>
    </tr>
  );
}
