import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import { normalizeMapPresentationProfile, normalizeMapPresentationProfiles } from "./map-presentation-profile.mjs";

const registry = JSON.parse(await readFile(new URL("../registry/map-presentation-profiles.json", import.meta.url), "utf8"));
const mapFixtureSource = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");
const catalogStyles = await readFile(new URL("../apps/catalog/src/styles.css", import.meta.url), "utf8");

test("canonical moving-object profile is provider-neutral and internally consistent", () => {
  assert.equal(registry.schemaVersion, "nodedc.map-presentation-profiles/v1");
  const profiles = normalizeMapPresentationProfiles(registry.profiles);
  assert.equal(profiles.length, 2);
  const profile = profiles.find((item) => item.id === "map.moving-object.operational.default");
  assert.ok(profile);
  assert.equal(profile.id, "map.moving-object.operational.default");
  assert.deepEqual(profile.semanticTypes, ["map.moving_object"]);
  assert.equal(profile.target.variant, "elevated-spike");
  assert.equal(profile.target.stemHeightMeters, 1500);
  assert.equal(profile.target.headSizePx, 9);
  assert.equal(profile.target.stemWidthPx, 5);
  assert.equal(profile.label.mode, "subject_id");
  assert.equal(profile.label.sizePx, 18);
  assert.equal(profile.label.backgroundOpacity, 0.86);
  assert.equal(profile.styles.find((style) => style.id === "online")?.color, "#86fdb8");
  assert.equal(profile.styles.find((style) => style.id === "moving")?.color, "#6fb5fb");
  assert.equal(JSON.stringify(profile).toLowerCase().includes("gelios"), false);
  assert.deepEqual(profile.facets.map((facet) => facet.field), [
    "availability_state",
    "motion_state",
  ]);
  assert.deepEqual(profile.facets.flatMap((facet) => facet.values.map((value) => value.label)), [
    "Онлайн",
    "Офлайн",
    "В движении",
    "Стоят",
  ]);
  assert.equal(JSON.stringify(profile).includes("Неизвестно"), false);
});

test("canonical zone profile renders provider-neutral surfaces", () => {
  const profiles = normalizeMapPresentationProfiles(registry.profiles);
  const profile = profiles.find((item) => item.id === "map.zone.operational.default");
  assert.ok(profile);
  assert.deepEqual(profile.semanticTypes, ["map.zone"]);
  assert.equal(profile.target.variant, "surface-fill");
  assert.equal(profile.label.mode, "attributes");
  assert.deepEqual(profile.facets.map((facet) => facet.field), ["geometry_kind", "source_kind"]);
  assert.equal(JSON.stringify(profile).toLowerCase().includes("gelios"), false);
  assert.equal(JSON.stringify(profile).includes("http"), false);
});

test("fleet filter window is one compact vertical list without group rows or All", () => {
  assert.match(mapFixtureSource, /catalog-map-fixture__target-filter-list/);
  assert.doesNotMatch(mapFixtureSource, /catalog-map-fixture__target-profile/);
  assert.doesNotMatch(mapFixtureSource, /catalog-map-fixture__target-facet/);
  assert.doesNotMatch(mapFixtureSource, />Все <span>/);
  assert.match(catalogStyles, /\.catalog-map-fixture__target-filter-list\s*\{[\s\S]*grid-template-columns:\s*minmax\(0, 1fr\)/);
  assert.match(catalogStyles, /\.catalog-map-fixture__target-filter-list button\s*\{[\s\S]*width:\s*100%/);
});

test("profile rejects undeclared state matches and renderer transport", () => {
  const source = registry.profiles[0];
  const undeclared = structuredClone(source);
  undeclared.classes[0].match[0].equals = "provider_magic";
  assert.throws(() => normalizeMapPresentationProfile(undeclared), /map_presentation_profile_class_condition_not_declared/);

  const transport = structuredClone(source);
  transport.providerUrl = "https://example.test";
  assert.throws(() => normalizeMapPresentationProfile(transport), /invalid_map_presentation_profile_fields/);
});

test("legacy pin profiles normalize into the provider-neutral target contract", () => {
  const legacy = structuredClone(registry.profiles[0]);
  legacy.pin = legacy.target;
  delete legacy.target;
  const normalized = normalizeMapPresentationProfile(legacy);
  assert.equal(normalized.target.stemHeightMeters, 1500);
  assert.equal(Object.hasOwn(normalized, "pin"), false);
});
