import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import { normalizeMapSubjectDetailProfile, normalizeMapSubjectDetailProfiles } from "./map-subject-detail-profile.mjs";

const registry = JSON.parse(await readFile(new URL("../registry/map-subject-detail-profiles.json", import.meta.url), "utf8"));

test("canonical subject detail profiles are provider-neutral and valid", () => {
  const profiles = normalizeMapSubjectDetailProfiles(registry.profiles);
  assert.equal(profiles.length, 1);
  assert.equal(profiles[0].id, "map.subject-detail.operational.default");
  assert.deepEqual(profiles[0].tabs.map((tab) => tab.id), [
    "overview", "position", "telemetry", "counters", "equipment", "settings", "maintenance", "diagnostics",
  ]);
});

test("dynamic sensor readings are fail-closed until ids are explicitly classified", () => {
  const profile = normalizeMapSubjectDetailProfile(registry.profiles[0]);
  const field = profile.tabs.find((tab) => tab.id === "telemetry").sections[0].fields[0];
  assert.equal(field.format, "telemetry_readings");
  assert.deepEqual(field.allowedReadingIds, []);
});

test("restricted fields and reading ids cannot be introduced through MCP profiles", () => {
  const restrictedField = structuredClone(registry.profiles[0]);
  restrictedField.tabs[0].sections[0].fields[0].field = "api_key";
  assert.throws(() => normalizeMapSubjectDetailProfile(restrictedField), /map_subject_detail_profile_secret_field/);

  const restrictedReading = structuredClone(registry.profiles[0]);
  restrictedReading.tabs.find((tab) => tab.id === "telemetry").sections[0].fields[0].allowedReadingIds = ["sensor.imei"];
  assert.throws(() => normalizeMapSubjectDetailProfile(restrictedReading), /map_subject_detail_profile_restricted_reading_id/);
});

test("restricted identifiers require an explicit restricted presentation class", () => {
  const profile = structuredClone(registry.profiles[0]);
  const field = profile.tabs[0].sections[0].fields[0];
  field.field = "device_phone_primary";
  field.label = "Телефон 1";
  assert.throws(
    () => normalizeMapSubjectDetailProfile(profile),
    /map_subject_detail_profile_restricted_field/,
  );
  field.dataClass = "restricted";
  assert.equal(
    normalizeMapSubjectDetailProfile(profile).tabs[0].sections[0].fields[0].dataClass,
    "restricted",
  );
});

test("string list fields are provider-neutral attribute presentations", () => {
  const profile = structuredClone(registry.profiles[0]);
  const field = profile.tabs[0].sections[0].fields[0];
  field.field = "custom_fields";
  field.label = "Пользовательские поля";
  field.format = "string_list";
  assert.equal(
    normalizeMapSubjectDetailProfile(profile).tabs[0].sections[0].fields[0].format,
    "string_list",
  );
  field.source = "fact";
  field.field = "sourceId";
  assert.throws(
    () => normalizeMapSubjectDetailProfile(profile),
    /map_subject_detail_profile_string_list_source_invalid/,
  );
});

test("profiles reject unknown schema fields and duplicate presentation ids", () => {
  const unknown = structuredClone(registry.profiles[0]);
  unknown.provider = "gelios";
  assert.throws(() => normalizeMapSubjectDetailProfile(unknown), /invalid_map_subject_detail_profile_fields/);

  const duplicate = structuredClone(registry.profiles[0]);
  duplicate.tabs[1].sections[0].fields[0].id = duplicate.tabs[0].sections[0].fields[0].id;
  assert.throws(() => normalizeMapSubjectDetailProfile(duplicate), /duplicate_map_subject_detail_profile_field_id/);
});
