import { useEffect, useMemo, useState } from "react";
import { StatusBadge } from "@nodedc/ui-react";

import {
  fetchDatasetNativeScanPreview,
  type DatasetNativeScanPreview,
} from "../core/lidar/datasetGateway";
import {
  LidarGroundPointCloud,
  type LidarGroundViewMode,
} from "./LidarGroundPointCloud";

const modes: ReadonlyArray<[LidarGroundViewMode, string]> = [
  ["intensity", "Исходный скан"],
  ["semantic", "Классы RELLIS"],
  ["ground-truth", "Ground target"],
];

function formatPercent(value: number): string {
  return new Intl.NumberFormat("ru-RU", {
    style: "percent",
    maximumFractionDigits: 1,
  }).format(value);
}

function errorMessage(error: unknown): string {
  return error instanceof Error && error.message.trim()
    ? error.message
    : "Официальный пример RELLIS недоступен.";
}

function modeExplanation(mode: LidarGroundViewMode): string {
  if (mode === "semantic") {
    return "Цвета из закреплённой официальной ontology RELLIS-3D.";
  }
  if (mode === "ground-truth") {
    return "Зелёный — ground, серый — non-ground, янтарный — ignore.";
  }
  return "Один исходный оборот Ouster OS1 64; цвет — нормализованная remission.";
}

export function RellisDatasetReview() {
  const [preview, setPreview] = useState<DatasetNativeScanPreview | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [mode, setMode] = useState<LidarGroundViewMode>("semantic");

  useEffect(() => {
    const controller = new AbortController();
    setError(null);
    void fetchDatasetNativeScanPreview({
      sourceId: "rellis-3d/v1.1",
      signal: controller.signal,
    })
      .then((value) => {
        if (!controller.signal.aborted) setPreview(value);
      })
      .catch((loadError: unknown) => {
        if (!controller.signal.aborted) setError(errorMessage(loadError));
      });
    return () => controller.abort();
  }, []);

  const scene = useMemo(() => {
    if (!preview) return null;
    const empty = Array.from({ length: preview.pointCount }, () => 0);
    return {
      pointCount: preview.pointCount,
      pointsXyzM: preview.pointsXyzM,
      intensity0To255: preview.remission0To255,
      semanticRgb0To255: preview.semanticRgb0To255,
      masks: {
        currentGround: empty,
        currentAssigned: preview.evaluationMask,
        candidateGround: empty,
        candidateAssigned: preview.evaluationMask,
        disagreement: empty,
        groundTruthGround: preview.groundTruthGround,
        evaluationMask: preview.evaluationMask,
      },
    };
  }, [preview]);

  if (error) {
    return (
      <section className="polygon-review-unavailable">
        <StatusBadge tone="danger">Smoke preview недоступен</StatusBadge>
        <h3>RELLIS-3D не открыт</h3>
        <p>{error}</p>
      </section>
    );
  }

  if (!preview || !scene) {
    return (
      <section className="polygon-review-unavailable">
        <StatusBadge tone="accent">Проверяем пример</StatusBadge>
        <h3>Открываем официальный RELLIS scan</h3>
        <p>Исходные dataset bytes не переносятся в браузер.</p>
      </section>
    );
  }

  const evaluatedPoints = preview.evaluationMask.reduce(
    (total, value) => total + value,
    0,
  );
  const groundPoints = preview.groundTruthGround.reduce(
    (total, value, index) => total + value * (preview.evaluationMask[index] ?? 0),
    0,
  );
  const groundClasses = preview.classes.filter(
    (item) => item.groundTarget === "ground",
  );
  const nonGroundClasses = preview.classes.filter(
    (item) => item.groundTarget === "non-ground",
  );
  const ignoredClasses = preview.classes.filter(
    (item) => item.groundTarget === "ignore",
  );

  return (
    <section
      className="dataset-sequence-review rellis-review"
      aria-label="Просмотр официального примера RELLIS-3D"
    >
      <header className="dataset-sequence-review__truth">
        <div>
          <span className="section-eyebrow">RELLIS S0 · COMPATIBILITY SMOKE</span>
          <h2>Официальный Ouster scan читается без конвертации формата</h2>
          <p>
            Frame {preview.frameId}: исходные XYZI и point-wise labels остались
            выровнены. Это проверка reader, осей, цветов и ground-policy — ещё не
            сравнение алгоритмов и не основание для навигации.
          </p>
        </div>
        <dl>
          <div>
            <dt>Исходных точек</dt>
            <dd>{preview.sourcePointCount.toLocaleString("ru-RU")}</dd>
          </div>
          <div>
            <dt>Browser preview</dt>
            <dd>{preview.pointCount.toLocaleString("ru-RU")}</dd>
          </div>
          <div>
            <dt>Sensor frame</dt>
            <dd>{preview.coordinateFrame?.frameId ?? "—"}</dd>
          </div>
        </dl>
      </header>

      <section className="polygon-review-player">
        <header className="polygon-review-player__header">
          <div>
            <span className="section-eyebrow">OFFICIAL EXAMPLE · FRAME 000104</span>
            <strong>Ouster OS1 64 · X forward · Y left · Z up</strong>
          </div>
          <div className="polygon-review-mode" aria-label="Режим RELLIS preview">
            {modes.map(([viewMode, label]) => (
              <button
                type="button"
                key={viewMode}
                data-active={mode === viewMode ? "true" : undefined}
                onClick={() => setMode(viewMode)}
              >
                {label}
              </button>
            ))}
          </div>
        </header>
        <div className="polygon-review-stage">
          <LidarGroundPointCloud
            frame={scene}
            mode={mode}
            coordinateFrame="sensor-fixed"
          />
          <div className="polygon-review-stage__legend">
            <strong>{modes.find(([viewMode]) => viewMode === mode)?.[1]}</strong>
            <span>{modeExplanation(mode)}</span>
          </div>
        </div>
      </section>

      <div className="rellis-review__metrics">
        <article>
          <span>Оценимых точек preview</span>
          <strong>{formatPercent(evaluatedPoints / preview.pointCount)}</strong>
          <small>ignore не участвует в метриках</small>
        </article>
        <article>
          <span>Ground среди оценимых</span>
          <strong>
            {formatPercent(evaluatedPoints ? groundPoints / evaluatedPoints : 0)}
          </strong>
          <small>версионная mapping policy v1</small>
        </article>
        <article>
          <span>Классов в этом scan</span>
          <strong>{preview.classes.length}</strong>
          <small>из 20 классов ontology</small>
        </article>
      </div>

      <section className="rellis-review__policy" aria-label="Ground target mapping">
        <header>
          <span className="section-eyebrow">GROUND TARGET POLICY V1</span>
          <h3>Что именно будет оцениваться</h3>
          <p>
            Mapping принадлежит Mission Core и версионируется отдельно от
            ontology датасета. Вода, лужи, void, sky и неопределённый object не
            засчитываются ни как ground, ни как obstacle.
          </p>
        </header>
        <div>
          <article>
            <span>Ground</span>
            <strong>{groundClasses.map((item) => item.className).join(" · ") || "—"}</strong>
          </article>
          <article>
            <span>Non-ground</span>
            <strong>
              {nonGroundClasses.map((item) => item.className).join(" · ") || "—"}
            </strong>
          </article>
          <article>
            <span>Ignore</span>
            <strong>{ignoredClasses.map((item) => item.className).join(" · ") || "—"}</strong>
          </article>
        </div>
      </section>

      <p className="dataset-sequence-review__raw-note">
        Лицензия RELLIS-3D — CC-BY-NC-SA-3.0: источник годится для независимой
        исследовательской проверки, но коммерческое использование данных или
        производных моделей требует отдельного лицензионного решения.
      </p>
    </section>
  );
}
