"use client";

/**
 * StreetDealsCard — «По вашей улице» — ДКП-сделки Росреестра по улице target адреса
 * с привязкой к историческим listings (Avito / Cian / Yandex / ДомКлик).
 *
 * Питается от GET /api/v1/trade-in/sales-vs-listings (PR L / #564 Phase 2).
 * Endpoint = superset предыдущего /street-deals: возвращает все pairs (LEFT JOIN
 * deal → listing) + linkage_rate. Aggregates (count / median / range) считаются
 * client-side по pairs[].deal_price_rub.
 *
 * Не рендерится если street не извлёкся или pairs.length = 0.
 */
import { useSalesVsListings } from "@/lib/trade-in-api";
import { openRosreestrWithAddress } from "@/lib/rosreestr";
import { safeUrl } from "@/lib/safeUrl";
import type { AggregatedEstimate, SalesListingPair } from "@/types/trade-in";

interface Props {
  estimate: AggregatedEstimate;
}

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

function fmtDate(iso: string | null): string {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleDateString("ru-RU", {
      day: "2-digit",
      month: "2-digit",
      year: "2-digit",
    });
  } catch {
    return "—";
  }
}

/** Median по числовому массиву (linear interpolation between centre items). */
function median(values: number[]): number {
  if (values.length === 0) return 0;
  const sorted = [...values].sort((a, b) => a - b);
  const mid = sorted.length / 2;
  if (Number.isInteger(mid)) {
    return (sorted[mid - 1] + sorted[mid]) / 2;
  }
  return sorted[Math.floor(mid)];
}

/** Срок «за N дней до» / «через N дней после» сделки. */
function fmtDaysToDeal(days: number | null): string {
  if (days === null) return "—";
  const abs = Math.abs(days);
  // Положительное = listing раньше сделки (типичный случай: «за 45 дней до»).
  // Отрицательное = listing появился позже сделки (отложенный парсинг, rare).
  return days >= 0 ? `за ${abs} дн до` : `через ${abs} дн после`;
}

/** Формат discount_pct со знаком и одной десятичной. */
function fmtDiscount(pct: number): string {
  const sign = pct > 0 ? "+" : pct < 0 ? "−" : "";
  return `${sign}${Math.abs(pct).toFixed(1)}%`;
}

export function StreetDealsCard({ estimate }: Props) {
  const { data, isLoading, isError } = useSalesVsListings(
    estimate.target_address ?? null,
    estimate.area_m2 ?? null,
    estimate.rooms ?? null,
  );

  if (isLoading || isError) return null;
  if (!data || !data.street || data.pairs.length === 0) return null;

  // Client-side aggregates по deal_price_rub / deal_price_per_m2 — endpoint
  // /sales-vs-listings не возвращает их (только linkage-связанные).
  const prices = data.pairs.map((p) => p.deal_price_rub);
  const ppm2Values = data.pairs.map((p) => p.deal_price_per_m2);
  const medianPpm2 = Math.round(median(ppm2Values));
  const rangeLow = Math.min(...prices);
  const rangeHigh = Math.max(...prices);
  const rangeLowM = (rangeLow / 1_000_000).toFixed(1);
  const rangeHighM = (rangeHigh / 1_000_000).toFixed(1);

  const hasAnyListing = data.deals_with_listings > 0;
  const visiblePairs: SalesListingPair[] = data.pairs.slice(0, 10);

  return (
    <article className="card">
      <div className="card-head">
        <div>
          <div className="section-kicker">Секция · По вашей улице</div>
          <h2>ДКП-сделки на улице {data.street}</h2>
          {hasAnyListing && (
            <div className="linkage-hint">
              <b className="mono">{data.linkage_rate_pct.toFixed(0)}%</b> сделок имеют
              исторический ASK
              {data.median_discount_pct !== null && (
                <>
                  {" · медианный торг "}
                  <b
                    className={
                      data.median_discount_pct < 0
                        ? "discount-neg mono"
                        : data.median_discount_pct > 0
                          ? "discount-pos mono"
                          : "mono"
                    }
                  >
                    {fmtDiscount(data.median_discount_pct)}
                  </b>
                </>
              )}
            </div>
          )}
          {data.data_quality === "street_only" && (
            <div className="linkage-hint">
              Данные по улице, не по конкретному дому: привязать сделки ДКП к
              отдельному объявлению по этому адресу нельзя — показаны все сделки
              на улице.
            </div>
          )}
        </div>
        <div className="card-meta">
          <div>
            Период: <b className="mono">{data.period_months} мес</b>
          </div>
          <div style={{ marginTop: 4 }}>источник: Росреестр + объявления</div>
        </div>
      </div>

      <div className="count-strip">
        <div className="count-cell">
          <div className="label">Сделок за {data.period_months} мес</div>
          <div className="value">
            <span data-tnum>{data.total_deals}</span>
            <span className="unit">шт</span>
          </div>
        </div>
        <div className="count-cell">
          <div className="label">Медиана</div>
          <div className="value">
            <span data-tnum>{fmtRub(medianPpm2)}</span>
            <span className="unit">₽/м²</span>
          </div>
        </div>
        <div className="count-cell">
          <div className="label">Диапазон</div>
          <div className="value">
            <span data-tnum>
              {rangeLowM} – {rangeHighM}
            </span>
            <span className="unit">млн ₽</span>
          </div>
        </div>
      </div>

      <table className="dt dt-with-asks" aria-label="Сделки по улице с историческим ASK">
        <thead>
          <tr>
            <th>Адрес</th>
            <th className="num">Площадь</th>
            <th className="num">Цена сделки</th>
            <th className="num">₽/м²</th>
            <th className="num">Дата</th>
            {hasAnyListing && <th>Объявление до сделки</th>}
            <th><span className="sr-only">Действия</span></th>
          </tr>
        </thead>
        <tbody>
          {visiblePairs.map((p) => {
            const safeListingUrl = safeUrl(p.listing_source_url);
            const hasListing = p.listing_id !== null && p.listing_price_rub !== null;
            return (
              <tr key={p.deal_id}>
                <td>
                  <span className="addr">
                    <span className="a-main">{p.deal_address}</span>
                  </span>
                </td>
                <td className="num">{p.deal_area_m2.toFixed(1)} м²</td>
                <td className="num">{fmtRub(p.deal_price_rub)} ₽</td>
                <td className="num">{fmtRub(p.deal_price_per_m2)}</td>
                <td className="num">{fmtDate(p.deal_date)}</td>
                {hasAnyListing && (
                  <td className="listing-cell">
                    {hasListing ? (
                      <ListingBadge
                        source={p.listing_source}
                        url={safeListingUrl}
                        priceRub={p.listing_price_rub}
                        daysToDeal={p.days_listing_to_deal}
                        discountPct={p.discount_pct}
                      />
                    ) : (
                      <span className="listing-empty">—</span>
                    )}
                  </td>
                )}
                <td>
                  <button
                    type="button"
                    className="rosreestr-btn"
                    onClick={() => void openRosreestrWithAddress(p.deal_address)}
                    title="Скопировать адрес и открыть форму запроса выписки ЕГРН"
                  >
                    Росреестр ↗
                  </button>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>

      <div className="table-foot">
        <span>
          Показано{" "}
          <b style={{ color: "var(--fg)" }}>{visiblePairs.length}</b> из{" "}
          <b style={{ color: "var(--fg)" }}>{data.total_deals}</b> сделок
        </span>
      </div>
    </article>
  );
}

// ── Listing badge cell ───────────────────────────────────────────────────────

interface ListingBadgeProps {
  source: string | null;
  url: string | null;
  priceRub: number | null;
  daysToDeal: number | null;
  discountPct: number | null;
}

function ListingBadge({
  source,
  url,
  priceRub,
  daysToDeal,
  discountPct,
}: ListingBadgeProps) {
  const sourceLabel = source ? source.toUpperCase() : "—";
  // discount < 0 → продано дешевле выставленного (типичный торг, success).
  // discount > 0 → продано дороже выставленного (редко, обычно ошибка data, danger).
  const discountClass =
    discountPct === null
      ? ""
      : discountPct < 0
        ? "discount-neg"
        : discountPct > 0
          ? "discount-pos"
          : "";

  const inner = (
    <>
      <span className="listing-source-badge">{sourceLabel}</span>
      <span className="listing-price mono">
        {priceRub !== null ? `${fmtRub(priceRub)} ₽` : "—"}
      </span>
      <span className="listing-meta">
        {fmtDaysToDeal(daysToDeal)}
        {discountPct !== null && (
          <>
            {" · "}
            <b className={`${discountClass} mono`}>{fmtDiscount(discountPct)}</b>
          </>
        )}
      </span>
    </>
  );

  if (url) {
    return (
      <a
        className="listing-link"
        href={url}
        target="_blank"
        rel="noopener noreferrer"
        title={`Открыть объявление на ${sourceLabel.toLowerCase()}`}
      >
        {inner}
      </a>
    );
  }

  return <span className="listing-link is-static">{inner}</span>;
}
