"use client";

/**
 * 6.4 Рекомендация по продукту — §13.4 product_tz (#953/#983).
 *
 * The literal answer to «что строить на участке»: рекомендованный класс (pill) +
 * квартирография (горизонтальные bar'ы по дефициту форматов) + коммерческий
 * сигнал + USP-ниши + §16-обоснование (раскрываемое).
 *
 * Quartirografiya is rendered as pure-Tailwind/token width-% bars (mobile-first,
 * NOT a pie): bar length = |deficit_index| (or `pct` when an explicit mix carries
 * shares), colour = deficit semantics (>0 недонасыщенность success, <0 затоварка
 * danger, ≈0 баланс neutral) — same mapping as 6.1.
 *
 * GRACEFUL: returns null when product_tz is absent/empty; each sub-field is
 * guarded individually so a thin/partial section never crashes.
 */

import type {
  ProductCommercial,
  ProductMixEntry,
  ProductReason,
  ProductUsp,
  ReportProductTz,
} from "@/types/forecast";

import { Badge } from "@/components/ui/Badge";
import type { BadgeVariant } from "@/components/ui/Badge";
import {
  DEFICIT_BALANCE_EPS,
  deficitBarWidthPct,
  deficitVariant,
  deficitWord,
  fmtNum,
} from "./forecast-helpers";

interface Props {
  /** §13.4 section; the whole block is skipped when absent (see Section6Forecast). */
  productTz: ReportProductTz;
}

// Deficit BadgeVariant → bar-fill token. Semantic colours encode deficit sign
// (success/danger/neutral) — this is the documented viz exception (bar = signal).
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)",
};

function isNonEmpty(productTz: ReportProductTz): boolean {
  return (
    productTz.obj_class != null ||
    productTz.mix.length > 0 ||
    productTz.usp.length > 0 ||
    productTz.reasons.length > 0 ||
    (productTz.commercial != null &&
      (productTz.commercial.available != null ||
        !!productTz.commercial.caveat)) ||
    !!productTz.summary
  );
}

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

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      {/* Recommended class — prominent pill + summary line */}
      <ClassHeadline
        obj_class={productTz.obj_class}
        summary={productTz.summary}
      />

      {/* Квартирография — deficit/share bars */}
      <MixBars mix={productTz.mix} />

      {/* Коммерция */}
      <CommercialSignal commercial={productTz.commercial} />

      {/* USP-ниши */}
      <UspList usp={productTz.usp} />

      {/* §16 обоснование (раскрываемое) */}
      <ReasonsDisclosure reasons={productTz.reasons} />
    </div>
  );
}

// ── Recommended class ─────────────────────────────────────────────────────────

function ClassHeadline({
  obj_class,
  summary,
}: {
  obj_class: string | null;
  summary: string | null;
}) {
  if (obj_class == null && !summary) return null;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {obj_class != null && (
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={SUBHEAD_STYLE}>Рекомендованный класс</span>
          <Badge variant="info" size="md">
            {obj_class}
          </Badge>
        </div>
      )}
      {summary && (
        <p
          style={{
            margin: 0,
            fontSize: 13,
            lineHeight: 1.5,
            color: "var(--fg-secondary)",
          }}
        >
          {summary}
        </p>
      )}
    </div>
  );
}

// ── Квартирография (mix bars) ─────────────────────────────────────────────────

function mixLabel(m: ProductMixEntry): string {
  const bucket = m.bucket ?? "формат";
  return m.obj_class ? `${bucket} · ${m.obj_class}` : bucket;
}

function MixBars({ mix }: { mix: ProductMixEntry[] }) {
  // Keep only entries with something to plot (a share or a deficit signal).
  const rows = mix.filter((m) => m.pct != null || m.deficit_index != null);
  if (rows.length === 0) return null;

  // Prefer explicit shares (доли) when the mix carries them; else fall back to
  // the deficit signal as the bar driver (current overlay shape).
  const hasShares = rows.some((m) => m.pct != null);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <span style={SUBHEAD_STYLE}>
        Квартирография{hasShares ? "" : " · по дефициту форматов"}
      </span>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {rows.map((m, i) => (
          <MixBar
            key={`${m.bucket ?? "?"}-${m.obj_class ?? "?"}-${i}`}
            entry={m}
          />
        ))}
      </div>
      {!hasShares && (
        <p
          style={{
            margin: 0,
            fontSize: 12,
            lineHeight: 1.5,
            color: "var(--fg-tertiary)",
          }}
        >
          Длина полосы — сила сигнала по индексу дефицита: положительный
          (зелёный) — недонасыщенность, отрицательный (красный) — затоварка.
        </p>
      )}
    </div>
  );
}

function MixBar({ entry }: { entry: ProductMixEntry }) {
  const di = entry.deficit_index;
  // Width: explicit share if present, else deficit magnitude.
  const widthPct =
    entry.pct != null
      ? Math.max(0, Math.min(100, entry.pct))
      : di != null
        ? deficitBarWidthPct(di)
        : 0;
  const variant: BadgeVariant = di != null ? deficitVariant(di) : "neutral";
  const balanced = di != null && Math.abs(di) < DEFICIT_BALANCE_EPS;

  // Right-hand value: share % takes priority, else the signed deficit index.
  const valueStr =
    entry.pct != null
      ? `${fmtNum(entry.pct, entry.pct % 1 === 0 ? 0 : 1)}%`
      : di != null
        ? `${di > 0 ? "+" : ""}${fmtNum(di, 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",
          }}
        >
          {mixLabel(entry)}
        </span>
        <span
          style={{
            fontSize: 12,
            color: "var(--fg-secondary)",
            fontVariantNumeric: "tabular-nums",
            flexShrink: 0,
          }}
        >
          {valueStr}
          {di != null && entry.pct == null && (
            <span style={{ marginLeft: 6, color: "var(--fg-tertiary)" }}>
              {balanced ? "баланс" : deficitWord(di)}
            </span>
          )}
        </span>
      </div>
      <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={`${mixLabel(entry)}: ${valueStr}`}
      >
        <div
          style={{
            position: "absolute",
            insetBlock: 0,
            insetInlineStart: 0,
            width: `${widthPct}%`,
            background: BAR_FILL[variant],
            borderRadius: 6,
          }}
        />
      </div>
    </div>
  );
}

// ── Коммерция ─────────────────────────────────────────────────────────────────

function CommercialSignal({
  commercial,
}: {
  commercial: ProductCommercial | null;
}) {
  if (
    commercial == null ||
    (commercial.available == null && !commercial.caveat)
  ) {
    return null;
  }
  const available = commercial.available === true;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span style={SUBHEAD_STYLE}>Коммерция</span>
        {commercial.available != null && (
          <Badge variant={available ? "success" : "neutral"} size="sm">
            {available ? "есть сигнал" : "нет данных"}
          </Badge>
        )}
      </div>
      {commercial.caveat && (
        <p
          style={{
            margin: 0,
            fontSize: 13,
            lineHeight: 1.5,
            color: "var(--fg-secondary)",
          }}
        >
          {capitalize(commercial.caveat)}
        </p>
      )}
    </div>
  );
}

// ── USP-ниши ──────────────────────────────────────────────────────────────────

function UspList({ usp }: { usp: ProductUsp[] }) {
  const items = usp.filter((u) => !!u.usp_text || !!u.segment);
  if (items.length === 0) return null;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <span style={SUBHEAD_STYLE}>УТП · ниши по дефициту ({items.length})</span>
      <ul
        style={{
          margin: 0,
          padding: 0,
          listStyle: "none",
          display: "flex",
          flexDirection: "column",
          gap: 6,
        }}
      >
        {items.map((u, i) => (
          <li
            key={`${u.segment ?? "?"}-${u.obj_class ?? "?"}-${i}`}
            style={{
              display: "flex",
              alignItems: "flex-start",
              gap: 8,
              padding: "8px 12px",
              background: "var(--bg-card-alt)",
              border: "1px solid var(--border-soft)",
              borderRadius: 8,
            }}
          >
            <span
              aria-hidden
              style={{
                marginTop: 7,
                width: 6,
                height: 6,
                borderRadius: "50%",
                background: "var(--accent)",
                flexShrink: 0,
              }}
            />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div
                style={{
                  fontSize: 13,
                  lineHeight: 1.5,
                  color: "var(--fg-primary)",
                }}
              >
                {u.usp_text ?? uspFallbackText(u)}
              </div>
              {u.deficit_index != null && (
                <div
                  style={{
                    fontSize: 12,
                    color: "var(--fg-tertiary)",
                    marginTop: 2,
                    fontVariantNumeric: "tabular-nums",
                  }}
                >
                  Индекс дефицита {u.deficit_index > 0 ? "+" : ""}
                  {fmtNum(u.deficit_index, 2)}
                </div>
              )}
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

function uspFallbackText(u: ProductUsp): string {
  const seg = u.segment ?? "формат";
  return u.obj_class ? `Ниша: ${seg} (${u.obj_class}).` : `Ниша: ${seg}.`;
}

// ── §16 обоснование (раскрываемое) ────────────────────────────────────────────

function ReasonsDisclosure({ reasons }: { reasons: ProductReason[] }) {
  const items = reasons.filter(
    (r) =>
      !!r.why ||
      (r.rejected?.length ?? 0) > 0 ||
      (r.what_would_change?.length ?? 0) > 0,
  );
  if (items.length === 0) return null;

  return (
    <details
      style={{
        borderTop: "1px solid var(--border-soft)",
        paddingTop: 12,
      }}
    >
      <summary
        style={{
          cursor: "pointer",
          fontSize: 12,
          fontWeight: 500,
          letterSpacing: "0.04em",
          textTransform: "uppercase",
          color: "var(--fg-secondary)",
          listStyle: "none",
        }}
      >
        Обоснование рекомендации
      </summary>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 12,
          marginTop: 12,
        }}
      >
        {items.map((r, i) => (
          <ReasonCard key={i} reason={r} />
        ))}
      </div>
    </details>
  );
}

function ReasonCard({ reason }: { reason: ProductReason }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {reason.why && (
        <p
          style={{
            margin: 0,
            fontSize: 13,
            lineHeight: 1.5,
            color: "var(--fg-primary)",
          }}
        >
          {reason.why}
        </p>
      )}

      {reason.rejected && reason.rejected.length > 0 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          <span style={SUBHEAD_STYLE}>Отвергнутые альтернативы</span>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {reason.rejected.map((rej, i) => (
              <span
                key={`${rej.alternative}-${i}`}
                style={{
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 6,
                  fontSize: 12,
                  color: "var(--fg-secondary)",
                  background: "var(--bg-card-alt)",
                  border: "1px solid var(--border-soft)",
                  borderRadius: 6,
                  padding: "3px 8px",
                }}
              >
                <span style={{ color: "var(--fg-primary)" }}>
                  {rej.alternative}
                </span>
                {rej.deficit_index != null && (
                  <span style={{ fontVariantNumeric: "tabular-nums" }}>
                    {rej.deficit_index > 0 ? "+" : ""}
                    {fmtNum(rej.deficit_index, 2)}
                  </span>
                )}
                <span style={{ color: "var(--fg-tertiary)" }}>
                  · {rej.reason}
                </span>
              </span>
            ))}
          </div>
        </div>
      )}

      {reason.what_would_change && reason.what_would_change.length > 0 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          <span style={SUBHEAD_STYLE}>Что изменит вывод</span>
          <ul
            style={{
              margin: 0,
              paddingInlineStart: 18,
              display: "flex",
              flexDirection: "column",
              gap: 3,
            }}
          >
            {reason.what_would_change.map((w, i) => (
              <li
                key={i}
                style={{
                  fontSize: 12,
                  lineHeight: 1.5,
                  color: "var(--fg-secondary)",
                }}
              >
                {w}
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

// ── helpers ───────────────────────────────────────────────────────────────────

function capitalize(text: string): string {
  return text.charAt(0).toUpperCase() + text.slice(1);
}
