"use client";

import { useMemo } from "react";

import type { RecommendBucket, RecommendMixOutput } from "@/types/analytics";

interface DerivedBucket extends RecommendBucket {
  effective_share_pct: number;
  effective_units: number | null;
  effective_revenue_rub: number | null;
}

interface Props {
  scope: RecommendMixOutput["scope"];
  derivedRows: DerivedBucket[];
  priceFactor: number;
  onPriceFactorChange: (next: number) => void;
  targetMonths: number | null;
  /** Set when user wants the system to suggest required price_factor. */
  onTargetMonthsApply?: () => void;
  hasAllocation: boolean;
}

const fmtMln = (rub: number | null) =>
  rub == null ? "—" : `${(rub / 1_000_000).toFixed(1)}`;

/**
 * Live "цена↔темп↔срок↔ликвидность" calculator.
 *
 * Все расчёты — клиентские по базовым коэффициентам из API:
 *   velocity_at_pf = velocity_base × price_factor^elasticity
 *   months_to_sellout = units / velocity_at_pf
 *   liquidity = avg(min(1, 24/months) × units) / total_units × 100
 *
 * Никаких round-trip к backend на каждое движение слайдера.
 */
export function RecommendVelocityPanel({
  scope,
  derivedRows,
  priceFactor,
  onPriceFactorChange,
  targetMonths,
  hasAllocation,
}: Props) {
  const elasticity = scope.elasticity;
  const pfPow = useMemo(
    () => (priceFactor > 0 ? priceFactor ** elasticity : 1),
    [priceFactor, elasticity],
  );

  // Aggregate live recompute. Темп и сроки считаем per-bucket с СВОЕЙ
  // эластичностью (Tier 3) — потому что Студии и 80+ м² реагируют на цену
  // по-разному. pfPow выше — fallback для bucket'ов без своей эластичности.
  const totals = useMemo(() => {
    let units = 0;
    let revenue = 0;
    let baseVelocity = 0; // sum of bucket velocity at price_factor=1
    let adjustedVelocity = 0; // sum of bucket velocity × bucket-specific pf^e
    let weightedSold24 = 0;
    for (const r of derivedRows) {
      const u = r.effective_units ?? 0;
      units += u;
      const baseRev = r.effective_revenue_rub ?? 0;
      revenue += baseRev * priceFactor;
      const v = r.velocity_per_month ?? 0;
      const shareRatio = r.effective_share_pct / Math.max(r.share_pct, 0.01);
      baseVelocity += v * shareRatio;
      const be = r.elasticity ?? elasticity;
      const bucketPfPow = priceFactor > 0 ? priceFactor ** be : 1;
      const adjustedV = v * bucketPfPow;
      adjustedVelocity += adjustedV * shareRatio;
      // Liquidity-24 KPI должен совпадать с точкой кривой
      // RecommendLiquidityChart на 24 мес (подпись секции обещает равенство).
      // График считает sellout по ЕДИНОЙ scope-эластичности (v × pfPow),
      // поэтому здесь тоже используем pfPow, а не per-bucket bucketPfPow.
      const liquidityV = v * pfPow;
      if (u > 0 && liquidityV > 0) {
        const months = u / liquidityV;
        const fracIn24 = Math.min(1, 24 / months);
        weightedSold24 += fracIn24 * u;
      }
    }
    const tempo =
      adjustedVelocity > 0 ? adjustedVelocity : baseVelocity * pfPow;
    const monthsToSellout = tempo > 0 && units > 0 ? units / tempo : null;
    const liquidity = units > 0 ? (weightedSold24 / units) * 100 : null;
    const avgTicket = units > 0 && revenue > 0 ? revenue / units : null;
    return {
      units,
      revenue,
      tempo,
      monthsToSellout,
      liquidity,
      avgTicket,
    };
  }, [derivedRows, priceFactor, pfPow, elasticity]);

  const liquidityColor =
    totals.liquidity == null
      ? "#9ca3af"
      : totals.liquidity >= 70
        ? "#0a7a3a"
        : totals.liquidity >= 40
          ? "#9a6700"
          : "#b3261e";

  const monthsLabel =
    totals.monthsToSellout == null
      ? "—"
      : totals.monthsToSellout > 60
        ? "60+"
        : totals.monthsToSellout.toFixed(1);

  // Preview required price_factor if target_months active
  const required = scope.required_price_factor;
  const requiredPct =
    required != null ? Math.round((required - 1) * 100) : null;

  return (
    <div>
      {/* Big KPI strip */}
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))",
          gap: 12,
          marginBottom: 16,
        }}
      >
        <BigKpi
          label="Средний чек"
          value={fmtMln(totals.avgTicket)}
          unit="М ₽"
        />
        <BigKpi
          label="Срок реализации"
          value={monthsLabel}
          unit="мес"
          hint={hasAllocation ? undefined : "укажи площадь"}
        />
        <BigKpi
          label="Темп продаж"
          value={totals.tempo > 0 ? totals.tempo.toFixed(1) : "—"}
          unit="кв/мес"
        />
        <BigKpi
          label="Ликвидность 24 мес"
          value={
            totals.liquidity != null ? `${totals.liquidity.toFixed(0)}` : "—"
          }
          unit="/ 100"
          color={liquidityColor}
        />
      </div>

      {/* #22 Noise penalty badge */}
      {scope.noise_penalty != null && scope.noise_penalty < 0.98 ? (
        <div
          style={{
            display: "inline-flex",
            alignItems: "center",
            gap: 4,
            marginBottom: 12,
          }}
        >
          <span
            style={{
              background: "#fef2f2",
              color: "#b91c1c",
              padding: "2px 8px",
              borderRadius: 6,
              fontSize: 11,
              fontWeight: 600,
              cursor: "default",
            }}
            title={(() => {
              const nb = scope.noise_breakdown;
              if (!nb || !("magistral_n" in nb)) return "нет данных";
              return (
                `Магистрали: ${nb.magistral_n} · ` +
                `ЖД: ${nb.railway_n} · ` +
                `Промзоны: ${nb.industrial_n} · ` +
                `Итого источников: ${nb.total_sources}`
              );
            })()}
          >
            {"🔊"} &minus;
            {scope.noise_breakdown && "penalty_pct" in scope.noise_breakdown
              ? scope.noise_breakdown.penalty_pct
              : Math.round((1 - scope.noise_penalty) * 100)}
            % (магистрали/жд/промзоны в районе)
          </span>
        </div>
      ) : null}

      {/* Warning badge — fallback на rosreestr (нет sale_graph для контекста) */}
      {scope.velocity_source === "rosreestr_fallback" ? (
        <div
          style={{
            padding: 10,
            marginTop: 4,
            marginBottom: 12,
            background: "#fef3c7",
            border: "1px solid #fcd34d",
            borderRadius: 8,
            fontSize: 13,
            color: "#92400e",
            lineHeight: 1.5,
          }}
        >
          ⚠ <strong>Темп грубый</strong> — нет sale_graph для ({scope.district}
          {scope.target_class ? ` · ${scope.target_class}` : ""}). Показано:
          city-wide rosreestr ({scope.total_deals} сделок /{" "}
          {scope.effective_window_months} мес) ÷ {scope.competitors_count}{" "}
          активных строящихся ЖК. Запусти 442-sweep по {scope.district} для
          точных данных.
        </div>
      ) : null}

      {/* Price factor slider — 0.01..3.0 (от -99% до +200%).
          min=0.01 (а не 0) чтобы избежать pf^elasticity = ∞ при свободной
          цене. */}
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "180px 1fr 110px",
          gap: 12,
          alignItems: "center",
          marginBottom: 8,
        }}
      >
        <span style={{ fontSize: 13, fontWeight: 600 }}>Цена ± к рынку</span>
        <input
          type="range"
          min={0.01}
          max={3.0}
          step={0.01}
          value={priceFactor}
          onChange={(e) => onPriceFactorChange(Number(e.target.value))}
        />
        <div style={{ textAlign: "right", fontSize: 14 }}>
          <span style={{ fontWeight: 700 }}>
            {priceFactor === 1
              ? "0%"
              : `${(priceFactor - 1) * 100 > 0 ? "+" : ""}${((priceFactor - 1) * 100).toFixed(0)}%`}
          </span>
          <div style={{ fontSize: 11, color: "#73767e" }}>
            ×{priceFactor.toFixed(2)}
          </div>
        </div>
      </div>

      {/* Inverse mode hint */}
      {targetMonths && required != null ? (
        <div
          style={{
            padding: 10,
            background:
              requiredPct != null && requiredPct < -15 ? "#fef2f2" : "#f0fdf4",
            border: `1px solid ${requiredPct != null && requiredPct < -15 ? "#fecaca" : "#bbf7d0"}`,
            borderRadius: 8,
            fontSize: 13,
            marginTop: 8,
            marginBottom: 8,
          }}
        >
          <strong>Целевой срок {targetMonths} мес</strong> требует price-factor{" "}
          <code
            style={{
              background: "rgba(0,0,0,0.05)",
              padding: "1px 5px",
              borderRadius: 3,
            }}
          >
            ×{required.toFixed(2)}
          </code>{" "}
          ({requiredPct !== null && requiredPct >= 0 ? "+" : ""}
          {requiredPct}% к рынку).{" "}
          <button
            onClick={() =>
              onPriceFactorChange(Math.max(0.01, Math.min(3.0, required)))
            }
            style={{
              padding: "2px 8px",
              fontSize: 12,
              border: "1px solid #d1d5db",
              borderRadius: 4,
              background: "#fff",
              cursor: "pointer",
              marginLeft: 8,
            }}
          >
            Применить →
          </button>
        </div>
      ) : null}

      {/* Cadastre vs market cross-check (NSPD ↔ rosreestr) */}
      {scope.cadastre_median_per_m2 != null &&
      scope.cadastre_vs_market_pct != null
        ? (() => {
            const pct = scope.cadastre_vs_market_pct;
            const isAnomaly = pct > 50 || pct < -30;
            const bg = isAnomaly ? "#fef2f2" : "#f0fdf4";
            const border = isAnomaly ? "#fecaca" : "#bbf7d0";
            const fg = isAnomaly ? "#b3261e" : "#0a7a3a";
            return (
              <div
                style={{
                  marginTop: 12,
                  padding: 8,
                  background: bg,
                  border: `1px solid ${border}`,
                  borderRadius: 6,
                  fontSize: 12,
                  lineHeight: 1.4,
                }}
                title={`Спред NSPD-кадастра и rosreestr-сделок. Норма: 0..+50% (рынок справедливо дороже кадастра, тк кадастр обычно отстаёт). Аномалии: >+50% (переоценка рынка) или <-30% (рынок дешевле кадастра, странно).`}
              >
                <strong>Кадастр vs Рынок: </strong>
                кадастровая медиана{" "}
                <strong>
                  {(scope.cadastre_median_per_m2 / 1000).toFixed(0)} тыс ₽/м²
                </strong>{" "}
                (по {scope.cadastre_buildings_n} зданиям NSPD), рынок{" "}
                <strong>
                  {scope.district_median_price_per_m2 != null
                    ? `${(scope.district_median_price_per_m2 / 1000).toFixed(0)} тыс ₽/м²`
                    : "—"}
                </strong>
                {" → "}
                <strong style={{ color: fg }}>
                  {pct > 0 ? "+" : ""}
                  {pct.toFixed(0)}%
                </strong>
                {isAnomaly ? (
                  <span
                    style={{
                      marginLeft: 6,
                      padding: "1px 6px",
                      background: "#fff",
                      border: `1px solid ${border}`,
                      borderRadius: 3,
                      color: fg,
                      fontWeight: 600,
                    }}
                  >
                    ⚠ Аномалия
                  </span>
                ) : null}
              </div>
            );
          })()
        : null}

      {/* Per-bucket elasticity breakdown — Tier 3 */}
      {scope.elasticity_per_bucket &&
      Object.keys(scope.elasticity_per_bucket).length > 0 ? (
        <div
          style={{
            marginTop: 12,
            padding: 8,
            background: "#f8fafc",
            border: "1px solid #e6e8ec",
            borderRadius: 6,
            fontSize: 11,
          }}
        >
          <div
            style={{
              fontWeight: 600,
              color: "#374151",
              marginBottom: 4,
              textTransform: "uppercase",
              letterSpacing: 0.4,
            }}
          >
            Эластичность по сегментам
          </div>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))",
              gap: 6,
            }}
          >
            {Object.entries(scope.elasticity_per_bucket).map(([b, info]) => {
              const isRegr = info.source === "regression";
              return (
                <div
                  key={b}
                  style={{
                    background: "#fff",
                    padding: "4px 6px",
                    borderRadius: 4,
                    border: `1px solid ${isRegr ? "#bbf7d0" : "#e6e8ec"}`,
                  }}
                  title={
                    isRegr
                      ? `regression: R²=${info.r2.toFixed(2)}, n=${info.n}`
                      : `fallback (общая эластичность ${elasticity}); n=${info.n} мало для регрессии`
                  }
                >
                  <span style={{ color: "#5b6066" }}>{b}: </span>
                  <strong style={{ color: isRegr ? "#0a7a3a" : "#9a6700" }}>
                    {info.elasticity.toFixed(2)}
                  </strong>
                  {isRegr ? (
                    <span style={{ color: "#9ca3af", marginLeft: 4 }}>
                      (n={info.n})
                    </span>
                  ) : (
                    <span style={{ color: "#9ca3af", marginLeft: 4 }}>
                      (fb)
                    </span>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      ) : null}

      {/* #25 Success ranking banner */}
      {scope.success_ranking != null &&
      scope.success_ranking.length > 0 &&
      scope.success_ranking[0].success_score > 0 ? (
        <div
          style={{
            marginTop: 12,
            padding: "8px 12px",
            background: "#fefce8",
            border: "1px solid #fde68a",
            borderRadius: 8,
            fontSize: 13,
            color: "#78350f",
            lineHeight: 1.5,
          }}
        >
          💎 Рекомендация смещена в пользу{" "}
          <strong>{scope.success_ranking[0].bucket}</strong> — лучшая динамика в
          районе ({scope.success_ranking[0].n_deals} сделок, успех{" "}
          {scope.success_ranking[0].success_score.toFixed(2)})
        </div>
      ) : null}

      {/* Methodology note */}
      <div
        style={{
          fontSize: 11,
          color: "#73767e",
          marginTop: 12,
          paddingTop: 8,
          borderTop: "1px dashed #e6e8ec",
        }}
      >
        Эластичность цена↔темп <strong>{elasticity}</strong> (
        {scope.elasticity_source === "regression"
          ? `регрессия sale_graph за ${scope.elasticity_window_months} мес: R²=${scope.elasticity_r2.toFixed(2)}, n=${scope.elasticity_n}`
          : `по умолчанию — sale_graph недостаточно (n=${scope.elasticity_n})`}
        )
        {scope.elasticity_weighted != null &&
        Math.abs(scope.elasticity_weighted - elasticity) > 0.05
          ? ` · взвешенная по бакетам: ${scope.elasticity_weighted.toFixed(2)}`
          : ""}
        . Базовый темп{" "}
        <strong>{scope.market_velocity_per_month?.toFixed(1) ?? "—"}</strong>{" "}
        кв/мес (
        {scope.velocity_source === "objective" ||
        scope.velocity_source === "sale_graph"
          ? `${scope.velocity_source}: ${scope.velocity_objects} ЖК / ${scope.velocity_observations} точек`
          : "fallback на rosreestr-сделки"}
        ),{" "}
        {scope.competitors_radius_n != null &&
        scope.competitors_district_only_n != null ? (
          <span
            title="Дальние конкуренты в районе тоже создают спрос, но меньше близких. Учитываются с весом 0.6 при нормировке velocity."
            style={{ cursor: "help" }}
          >
            нормирован: в радиусе 3км{" "}
            <strong>{scope.competitors_radius_n} ЖК</strong> · дальше по району{" "}
            <strong>{scope.competitors_district_only_n} ЖК</strong> (вес 0.6)
          </span>
        ) : (
          <>
            нормирован на <strong>{scope.competitors_count}</strong> активных
            конкурентов в районе
          </>
        )}
        . Применены macro-факторы:{" "}
        <strong>sat ×{scope.sat_factor.toFixed(2)}</strong>
        {scope.saturation_median != null
          ? ` (sold% ${scope.saturation_median.toFixed(0)})`
          : ""}{" "}
        · <strong>trend ×{scope.trend_factor.toFixed(2)}</strong>
        {scope.velocity_trend_ratio != null
          ? ` (raw ×${scope.velocity_trend_ratio.toFixed(2)} clamp 0.7..2.0)`
          : ""}{" "}
        · <strong>POI ×{scope.poi_factor.toFixed(2)}</strong> (на цену) ). При
        price ×{priceFactor.toFixed(2)} ценовой множитель темпа по общей
        эластичности = {priceFactor.toFixed(2)}^{elasticity} = ×
        {pfPow.toFixed(3)}. Показанный «Темп продаж» суммирует бакеты с их
        собственной эластичностью (Tier 3) и текущим распределением долей,
        поэтому может отличаться от базовый ×{pfPow.toFixed(3)}.
      </div>
    </div>
  );
}

function BigKpi({
  label,
  value,
  unit,
  hint,
  color,
}: {
  label: string;
  value: string;
  unit?: string;
  hint?: string;
  color?: string;
}) {
  return (
    <div
      style={{
        background: "#fff",
        border: "1px solid #e6e8ec",
        borderRadius: 10,
        padding: "12px 14px",
      }}
    >
      <div
        style={{
          fontSize: 11,
          color: "#5b6066",
          textTransform: "uppercase",
          letterSpacing: 0.4,
          marginBottom: 4,
        }}
      >
        {label}
      </div>
      <div
        style={{
          fontSize: 24,
          fontWeight: 700,
          color: color ?? "#0f172a",
          lineHeight: 1.1,
        }}
      >
        {value}
        {unit ? (
          <span
            style={{
              fontSize: 13,
              fontWeight: 500,
              color: "#5b6066",
              marginLeft: 4,
            }}
          >
            {unit}
          </span>
        ) : null}
      </div>
      {hint ? (
        <div style={{ fontSize: 11, color: "#9ca3af", marginTop: 2 }}>
          {hint}
        </div>
      ) : null}
    </div>
  );
}
