"use client";

/**
 * Section6Forecast — "6. Прогноз" (958-B3 / §22).
 *
 * Renders the async §22 demand/supply forecast, scenarios and confidence on the
 * Site Finder analysis screen. Self-fetches via useParcelForecastQuery, which
 * POLLs GET /api/v1/parcels/{cad}/forecast every 4s until status === "ready"
 * (the forecast is enqueued by useParcelAnalyzeQuery on page mount — render-only
 * here, no trigger).
 *
 * Layout mirrors Section1-5: dark HeadlineBar + section root id="section-6".
 *   exec_summary banner (headline + verdict + KPI row)
 *   6.1 Прогноз по горизонтам    → ForecastHorizonsBlock
 *   6.2 Сценарии                 → ScenariosBlock
 *   6.3 Уверенность              → ForecastConfidenceBlock
 *   6.4 Рекомендация по продукту → ForecastProductTzBlock (что строить — §13.4)
 *   advisory disclaimer (footer)
 */

import { LineChart } from "lucide-react";

import { HeadlineBar } from "@/components/ui/HeadlineBar";
import { KpiCard } from "@/components/site-finder/KpiCard";
import { useParcelForecastQuery } from "@/lib/site-finder-api";
import type { ForecastReport } from "@/types/forecast";

import { ForecastChart } from "./ForecastChart";
import { ForecastHorizonsBlock } from "./ForecastHorizonsBlock";
import { ScenariosBlock } from "./ScenariosBlock";
import { ForecastConfidenceBlock } from "./ForecastConfidenceBlock";
import { ForecastProductTzBlock } from "./ForecastProductTzBlock";
import { ForecastExportButtons } from "./ForecastExportButtons";
import { CONFIDENCE_RU, deficitVariant, fmtNum } from "./forecast-helpers";

interface Props {
  cad: string;
  /**
   * Horizon chosen in the analysis-screen HorizonSelector (6 / 12 / 18). When
   * set it takes priority over the report-derived horizon so the user's choice
   * instantly drives which horizon is treated as the target (client-side), even
   * before the recomputed forecast finishes (see AnalysisPageContent comment).
   */
  selectedHorizon?: number;
}

const ADVISORY_DISCLAIMER =
  "Оценка advisory — не основание для инвест-решения.";

const SCROLL_MARGIN = 72;

// KpiCard color enum (site-finder variant) mapped from Badge variant words.
function kpiColorForDeficit(deficitIndex: number): "green" | "red" | "neutral" {
  const v = deficitVariant(deficitIndex);
  if (v === "success") return "green";
  if (v === "danger") return "red";
  return "neutral";
}

// ── Section6Forecast ─────────────────────────────────────────────────────────

export function Section6Forecast({ cad, selectedHorizon }: Props) {
  const { data, isLoading, error } = useParcelForecastQuery(cad);

  const isPending =
    isLoading || (data != null && data.status !== "ready") || data == null;

  // ── Pending: forecast still computing (poll in flight) ─────────────────────
  if (isPending && !error) {
    return (
      <section id="section-6" style={{ scrollMarginTop: SCROLL_MARGIN }}>
        <HeadlineBar
          title="6. Прогноз"
          subtitle="Прогноз спроса, предложения и сценарии (§22)."
        />
        <div
          style={{
            marginTop: 12,
            display: "flex",
            flexDirection: "column",
            gap: 12,
          }}
        >
          <div
            style={{
              borderRadius: 12,
              background: "var(--bg-card-alt)",
              border: "1px solid var(--border-soft)",
              padding: "24px 20px",
              textAlign: "center",
              color: "var(--fg-tertiary)",
              fontSize: 13,
            }}
          >
            Прогноз рассчитывается…
          </div>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
              gap: 12,
            }}
          >
            {[0, 1, 2].map((i) => (
              <div
                key={i}
                style={{
                  borderRadius: 12,
                  background: "var(--bg-card-alt)",
                  border: "1px solid var(--border-soft)",
                  height: 88,
                }}
                aria-hidden
              />
            ))}
          </div>
        </div>
      </section>
    );
  }

  // ── Error ──────────────────────────────────────────────────────────────────
  if (error || !data || data.status !== "ready" || !data.report) {
    return (
      <section id="section-6" style={{ scrollMarginTop: SCROLL_MARGIN }}>
        <HeadlineBar title="6. Прогноз" />
        <div
          style={{
            marginTop: 12,
            borderRadius: 12,
            padding: "32px 24px",
            background: "var(--bg-card-alt)",
            border: "1px dashed var(--border-strong)",
            textAlign: "center",
            color: "var(--fg-tertiary)",
            fontSize: 13,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            gap: 8,
          }}
        >
          <LineChart size={20} aria-hidden />
          Данные прогноза недоступны
        </div>
      </section>
    );
  }

  return (
    <ForecastReady
      cad={cad}
      report={data.report}
      selectedHorizon={selectedHorizon}
    />
  );
}

// ── ForecastReady (report present) ───────────────────────────────────────────

function ForecastReady({
  cad,
  report,
  selectedHorizon,
}: {
  cad: string;
  report: ForecastReport;
  selectedHorizon?: number;
}) {
  const exec = report.exec_summary;
  const fm = report.future_market;

  // Target horizon: the user's HorizonSelector choice wins (instant client-side
  // highlight), else future_supply.horizon_months, else median of meta horizons,
  // else 12.
  const targetHorizon =
    selectedHorizon ??
    fm.future_supply?.horizon_months ??
    medianHorizon(report.meta.horizons) ??
    12;

  const kn = exec.key_numbers;

  const hasHorizons = fm.forecasts_by_horizon.length > 0;
  const hasScenarios =
    Object.keys(report.scenarios.by_scenario).length > 0 ||
    fm.scenarios_summary != null;
  const hasConfidence =
    report.confidence.level != null ||
    Object.keys(report.confidence.factors).length > 0;

  // 6.4 — рекомендация продукта (§13.4). product_tz is optional on the partial
  // ForecastReport type; treat absent/thin section as "nothing to show".
  const pt = report.product_tz;
  const hasProductTz =
    pt != null &&
    (pt.obj_class != null ||
      pt.mix.length > 0 ||
      pt.usp.length > 0 ||
      pt.reasons.length > 0 ||
      !!pt.summary ||
      (pt.commercial != null &&
        (pt.commercial.available != null || !!pt.commercial.caveat)));

  const hasAny = hasHorizons || hasScenarios || hasConfidence || hasProductTz;

  // Headline subtitle = future_market summary (one sentence «откуда / что значит»).
  const subtitle = fm.summary ?? undefined;

  return (
    <section id="section-6" style={{ scrollMarginTop: SCROLL_MARGIN }}>
      <HeadlineBar title={exec.headline ?? "6. Прогноз"} subtitle={subtitle} />

      <div
        style={{
          marginTop: 12,
          display: "flex",
          flexDirection: "column",
          gap: 24,
        }}
      >
        {/* Export / share forecast report (EPIC #959) */}
        <ForecastExportButtons cad={cad} />

        {/* exec_summary verdict + KPI row */}
        {exec.verdict && (
          <p
            style={{
              margin: 0,
              fontSize: 14,
              lineHeight: 1.5,
              color: "var(--fg-primary)",
            }}
          >
            {exec.verdict}
          </p>
        )}

        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
            gap: 12,
          }}
        >
          <KpiCard
            label="Индекс дефицита"
            value={
              kn.deficit_index != null
                ? `${kn.deficit_index > 0 ? "+" : ""}${fmtNum(kn.deficit_index, 2)}`
                : "—"
            }
            color={
              kn.deficit_index != null
                ? kpiColorForDeficit(kn.deficit_index)
                : "neutral"
            }
          />
          <KpiCard
            label="Мес. предложения"
            value={
              kn.months_of_inventory != null
                ? fmtNum(kn.months_of_inventory, 1)
                : "—"
            }
            color="neutral"
          />
          <KpiCard
            label="Итоговый скор"
            value={kn.overall_score != null ? fmtNum(kn.overall_score, 2) : "—"}
            color="blue"
          />
          <KpiCard
            label="Уверенность"
            value={
              (exec.overall_confidence ?? kn.confidence) != null
                ? CONFIDENCE_RU[
                    (exec.overall_confidence ?? kn.confidence) as
                      | "high"
                      | "medium"
                      | "low"
                  ]
                : "—"
            }
            color={confidenceKpiColor(exec.overall_confidence ?? kn.confidence)}
          />
        </div>

        {!hasAny && (
          <div
            style={{
              borderRadius: 12,
              padding: "24px 20px",
              background: "var(--bg-card-alt)",
              border: "1px dashed var(--border-strong)",
              textAlign: "center",
              color: "var(--fg-tertiary)",
              fontSize: 13,
            }}
          >
            Данные прогноза недоступны
          </div>
        )}

        {/* Траектория индекса дефицита (chart-then-table, выше 6.1) */}
        <ForecastChart report={report} selectedHorizon={selectedHorizon} />

        {/* 6.1 Прогноз по горизонтам */}
        {hasHorizons && (
          <SubBlock id="section-6-1" title="6.1 Прогноз по горизонтам">
            <ForecastHorizonsBlock
              forecasts={fm.forecasts_by_horizon}
              targetHorizon={targetHorizon}
            />
          </SubBlock>
        )}

        {/* 6.2 Сценарии */}
        {hasScenarios && (
          <SubBlock id="section-6-2" title="6.2 Сценарии">
            <ScenariosBlock
              scenarios={report.scenarios}
              scenariosSummary={fm.scenarios_summary}
              targetHorizon={targetHorizon}
            />
          </SubBlock>
        )}

        {/* 6.3 Уверенность */}
        {hasConfidence && (
          <SubBlock id="section-6-3" title="6.3 Уверенность">
            <ForecastConfidenceBlock confidence={report.confidence} />
          </SubBlock>
        )}

        {/* 6.4 Рекомендация по продукту — что строить на участке (§13.4) */}
        {hasProductTz && pt && (
          <SubBlock id="section-6-4" title="6.4 Рекомендация по продукту">
            <ForecastProductTzBlock productTz={pt} />
          </SubBlock>
        )}

        {/* Advisory disclaimer */}
        <p
          style={{
            margin: 0,
            fontSize: 12,
            lineHeight: 1.5,
            color: "var(--fg-tertiary)",
            paddingTop: 12,
            borderTop: "1px solid var(--border-soft)",
          }}
        >
          {ADVISORY_DISCLAIMER}
        </p>
      </div>
    </section>
  );
}

// ── SubBlock wrapper (6.1 / 6.2 / 6.3) ───────────────────────────────────────

function SubBlock({
  id,
  title,
  children,
}: {
  id: string;
  title: string;
  children: React.ReactNode;
}) {
  return (
    <div id={id} style={{ scrollMarginTop: SCROLL_MARGIN }}>
      <h3
        style={{
          margin: "0 0 12px",
          fontSize: 14,
          fontWeight: 600,
          color: "var(--fg-primary)",
        }}
      >
        {title}
      </h3>
      <div
        style={{
          borderRadius: 12,
          border: "1px solid var(--border-card)",
          background: "var(--bg-card)",
          padding: 20,
        }}
      >
        {children}
      </div>
    </div>
  );
}

// ── Helpers ──────────────────────────────────────────────────────────────────

function medianHorizon(horizons: number[]): number | null {
  if (horizons.length === 0) return null;
  const sorted = [...horizons].sort((a, b) => a - b);
  return sorted[Math.floor(sorted.length / 2)];
}

function confidenceKpiColor(
  level: "high" | "medium" | "low" | null,
): "green" | "amber" | "red" | "neutral" {
  if (level === "high") return "green";
  if (level === "medium") return "amber";
  if (level === "low") return "red";
  return "neutral";
}
