"use client";

/**
 * 6.5 Прозрачность скоринга — §13.6 scoring (#985/#986).
 *
 * Explains WHY the overall score is what it is: the exec-summary KPI shows only
 * `scoring.overall` (single number) — this block surfaces the breakdown that
 * drives it. Two labeled groups of pure-Tailwind/token width-% bars (mobile-
 * first, NOT a pie):
 *
 *   • Продуктовые скоры (#985) — 10 scores, each value ∈ [0,1] with «выше =
 *     лучше для девелопера» (risk scores pre-inverted at the source). Bar width =
 *     value·100, colour = quality (scoreVariant: success / warning / danger).
 *   • Специальные индексы (#986) — 6 indices, each value ∈ [0,1] = СИЛА сигнала,
 *     NOT uniformly good/bad (cost_of_error / cannibalization / competitor_
 *     strength / artificial_demand grow toward worse; launch_window /
 *     product_void toward better). Direction is not uniform → NEUTRAL accent bar
 *     (we do not imply good/bad on an index whose valence depends on which one).
 *
 * GRACEFUL: returns null when scoring is absent/empty; product_scores empty →
 * that group is skipped; special_indices empty → skipped; rows with value=null
 * (thin/unavailable) render «нет данных» without a bar. Never crashes on a
 * partial / 202-pending report. The `overall` KPI is NOT duplicated here (shown
 * once in the exec-summary card) — only a small contextual sub-header echoes it.
 */

import type {
  ProductScore,
  ProductScoreCard,
  ReportScoring,
  SpecialIndex,
  SpecialIndicesCard,
} from "@/types/forecast";

import type { BadgeVariant } from "@/components/ui/Badge";
import {
  PRODUCT_SCORE_RU,
  SPECIAL_INDEX_DESC,
  SPECIAL_INDEX_RU,
  fmtNum,
  scoreBarWidthPct,
  scoreVariant,
  stripSectionRefs,
} from "./forecast-helpers";

// #1963 — порог баланса для общего вердикта по итоговому скору (0.5 = баланс).
const OVERALL_BALANCE = 0.5;

interface Props {
  /** §13.6 section; the whole block is skipped when absent (see Section6Forecast). */
  scoring: ReportScoring;
}

// BadgeVariant → bar-fill token. Semantic colours encode score quality
// (success/warning/danger) — documented viz exception (bar = signal). `info`
// (--accent) is the neutral/directionless fill used for special indices.
const BAR_FILL: Record<BadgeVariant, string> = {
  success: "var(--success)",
  danger: "var(--danger)",
  warning: "var(--warn)",
  info: "var(--accent)",
  neutral: "var(--border-strong)",
};

const SUBHEAD_STYLE: React.CSSProperties = {
  fontSize: 11,
  fontWeight: 500,
  letterSpacing: "0.04em",
  textTransform: "uppercase",
  color: "var(--fg-secondary)",
};

const HINT_STYLE: React.CSSProperties = {
  margin: 0,
  fontSize: 12,
  lineHeight: 1.5,
  color: "var(--fg-tertiary)",
};

// ── Predicates ─────────────────────────────────────────────────────────────────

function scoreRows(card: ProductScoreCard | null): ProductScore[] {
  if (card == null) return [];
  // Stable object insertion order = canonical _SCORE_KEYS order (assembler).
  return Object.values(card.scores).filter(
    (s): s is ProductScore => s != null && typeof s.key === "string",
  );
}

function indexRows(card: SpecialIndicesCard | null): SpecialIndex[] {
  if (card == null) return [];
  return Object.values(card.indices).filter(
    (i): i is SpecialIndex => i != null && typeof i.key === "string",
  );
}

function isNonEmpty(scoring: ReportScoring): boolean {
  return (
    scoreRows(scoring.product_scores).length > 0 ||
    indexRows(scoring.special_indices).length > 0
  );
}

// ── ForecastScoringBlock ─────────────────────────────────────────────────────────

export function ForecastScoringBlock({ scoring }: Props) {
  // Graceful: nothing meaningful to show → render nothing.
  if (!isNonEmpty(scoring)) return null;

  const scores = scoreRows(scoring.product_scores);
  const indices = indexRows(scoring.special_indices);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      {/* Contextual sub-header — echoes overall WITHOUT duplicating the KPI card. */}
      <p
        style={{
          margin: 0,
          fontSize: 13,
          lineHeight: 1.5,
          color: "var(--fg-secondary)",
        }}
      >
        {scoring.overall != null
          ? `Из чего сложился итоговый продуктовый скор ${fmtNum(scoring.overall, 2)} (∈ 0…1, выше — лучше).`
          : "Из чего складывается продуктовый скор (значения ∈ 0…1, выше — лучше)."}
      </p>

      {/* #1963 — общий вердикт по итоговому скору относительно баланса 0.5. */}
      {scoring.overall != null && (
        <p style={{ ...HINT_STYLE, color: "var(--fg-secondary)" }}>
          {scoring.overall < OVERALL_BALANCE
            ? `Итог ${fmtNum(scoring.overall, 2)} ниже баланса 0.5 — рынок для этого продукта скорее неблагоприятный.`
            : `Итог ${fmtNum(scoring.overall, 2)} на уровне баланса 0.5 или выше — рынок для этого продукта скорее благоприятный.`}
        </p>
      )}

      {/* Продуктовые скоры (#985) — quality gradient (higher = better). */}
      <ProductScoresGroup scores={scores} />

      {/* Специальные индексы (#986) — neutral accent (signal strength). */}
      <SpecialIndicesGroup indices={indices} />
    </div>
  );
}

// ── Продуктовые скоры (#985) ───────────────────────────────────────────────────

function ProductScoresGroup({ scores }: { scores: ProductScore[] }) {
  if (scores.length === 0) return null;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <span style={SUBHEAD_STYLE}>Продуктовые скоры ({scores.length})</span>
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {scores.map((s) => (
          <ScoreBar key={s.key} score={s} />
        ))}
      </div>
      <p style={HINT_STYLE}>
        Длина и цвет полосы — значение скора ∈ 0…1: зелёный — сильный, жёлтый —
        средний, красный — слабый. Риск-скоры уже инвертированы (выше всегда
        лучше).
      </p>
    </div>
  );
}

function ScoreBar({ score }: { score: ProductScore }) {
  const label = PRODUCT_SCORE_RU[score.key] ?? score.key;
  const value = score.value;
  const hasValue = value != null;
  const widthPct = hasValue ? scoreBarWidthPct(value) : 0;
  const variant: BadgeVariant = hasValue ? scoreVariant(value) : "neutral";
  const valueStr = hasValue ? fmtNum(value, 2) : "нет данных";

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 3 }}>
      <div
        style={{
          display: "flex",
          alignItems: "baseline",
          justifyContent: "space-between",
          gap: 12,
        }}
      >
        <span
          style={{
            fontSize: 13,
            color: "var(--fg-primary)",
            minWidth: 0,
            overflow: "hidden",
            textOverflow: "ellipsis",
            whiteSpace: "nowrap",
          }}
        >
          {label}
        </span>
        <span
          style={{
            fontSize: 12,
            color: hasValue ? "var(--fg-secondary)" : "var(--fg-tertiary)",
            fontVariantNumeric: "tabular-nums",
            flexShrink: 0,
          }}
        >
          {valueStr}
        </span>
      </div>
      <Track
        widthPct={widthPct}
        fill={BAR_FILL[variant]}
        ariaLabel={`${label}: ${valueStr}`}
      />
      {score.reason &&
        (() => {
          // #1963 — §-ссылки уводим из основного текста в title-тултип «детали».
          const { clean, refs } = stripSectionRefs(score.reason);
          return (
            <p
              style={{
                margin: 0,
                fontSize: 12,
                lineHeight: 1.45,
                color: "var(--fg-tertiary)",
              }}
              title={refs ? `Источник: ${refs}` : undefined}
            >
              {clean || score.reason}
            </p>
          );
        })()}
    </div>
  );
}

// ── Специальные индексы (#986) ─────────────────────────────────────────────────

function SpecialIndicesGroup({ indices }: { indices: SpecialIndex[] }) {
  if (indices.length === 0) return null;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <span style={SUBHEAD_STYLE}>Специальные индексы ({indices.length})</span>
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {indices.map((idx) => (
          <IndexBar key={idx.key} index={idx} />
        ))}
      </div>
      <p style={HINT_STYLE}>
        Длина полосы — сила сигнала индекса ∈ 0…1 (нейтральный цвет: направление
        зависит от индекса — часть растёт к лучшему, часть к худшему).
      </p>
    </div>
  );
}

function IndexBar({ index }: { index: SpecialIndex }) {
  const name = SPECIAL_INDEX_RU[index.key] ?? index.key;
  const value = index.value;
  const hasValue = value != null;
  const widthPct = hasValue ? scoreBarWidthPct(value) : 0;
  // Direction is not uniform across indices → neutral accent, no good/bad implied.
  const variant: BadgeVariant = hasValue ? "info" : "neutral";
  const valueStr = hasValue ? fmtNum(value, 2) : "нет данных";

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 3 }}>
      <div
        style={{
          display: "flex",
          alignItems: "baseline",
          justifyContent: "space-between",
          gap: 12,
        }}
      >
        <span
          style={{
            fontSize: 13,
            color: "var(--fg-primary)",
            minWidth: 0,
            overflow: "hidden",
            textOverflow: "ellipsis",
            whiteSpace: "nowrap",
          }}
        >
          {name}
          {index.label && (
            <span style={{ marginLeft: 6, color: "var(--fg-tertiary)" }}>
              · {index.label}
            </span>
          )}
        </span>
        <span
          style={{
            fontSize: 12,
            color: hasValue ? "var(--fg-secondary)" : "var(--fg-tertiary)",
            fontVariantNumeric: "tabular-nums",
            flexShrink: 0,
          }}
        >
          {valueStr}
        </span>
      </div>
      <Track
        widthPct={widthPct}
        fill={BAR_FILL[variant]}
        ariaLabel={`${name}: ${valueStr}`}
      />
      {/* #1963 — однострочное «что это + куда лучше» (направление у индексов разное). */}
      {SPECIAL_INDEX_DESC[index.key] && (
        <p
          style={{
            margin: 0,
            fontSize: 12,
            lineHeight: 1.45,
            color: "var(--fg-tertiary)",
          }}
        >
          {SPECIAL_INDEX_DESC[index.key]}
        </p>
      )}
    </div>
  );
}

// ── Shared bar track ───────────────────────────────────────────────────────────

function Track({
  widthPct,
  fill,
  ariaLabel,
}: {
  widthPct: number;
  fill: string;
  ariaLabel: string;
}) {
  return (
    <div
      style={{
        position: "relative",
        height: 8,
        borderRadius: 6,
        background: "var(--bg-card-alt)",
        border: "1px solid var(--border-soft)",
        overflow: "hidden",
      }}
      role="img"
      aria-label={ariaLabel}
    >
      <div
        style={{
          position: "absolute",
          insetBlock: 0,
          insetInlineStart: 0,
          width: `${widthPct}%`,
          background: fill,
          borderRadius: 6,
        }}
      />
    </div>
  );
}
