import assert from "node:assert/strict";
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { loadDataProductDefinitions } from "../src/definitions.mjs";

const bundled = await loadDataProductDefinitions();
assert.deepEqual(bundled.map((definition) => definition.id), [
  "fleet.positions.current.v1",
  "fleet.positions.current.v2",
  "fleet.positions.current.v3",
  "fleet.positions.current.v4",
  "fleet.positions.current.v5",
  "fleet.units.contacts.current.v1",
  "fleet.units.contacts.current.v2",
  "fleet.units.identity.current.v1",
  "fleet.units.profile.current.v1",
  "map.zones.current.v1",
  "map.zones.current.v2",
]);
assert.deepEqual(bundled[0].semanticTypes, ["map.moving_object"]);
assert.equal(bundled[0].ontologyRevision, "ontology.map.moving_object.v1");
assert.equal(bundled[0].history.mode, "sampled");
assert.equal(bundled[0].history.intervalMs, 60_000);
assert.equal(bundled[0].history.retentionDays, 90);
assert.equal(bundled[0].fields.includes("geometry"), true);
assert.equal(bundled[0].fields.includes("providerUnitId"), false);
assert.equal(bundled[0].fields.includes("provider_unit_id"), false);
assert.equal(bundled[1].version, "2.0.0");
assert.equal(bundled[1].ontologyRevision, "ontology.map.moving_object.v2");
assert.deepEqual(
  bundled[1].fields.filter((field) => field.endsWith("_state")),
  ["availability_state", "freshness_state", "motion_state", "position_state"],
);
assert.equal(bundled[2].version, "3.0.0");
assert.equal(bundled[2].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(
  bundled[2].fields.filter((field) => field.endsWith("_state")),
  ["movement_state", "signal_state"],
);
assert.equal(bundled[2].fields.includes("operational_status"), false);
assert.equal(bundled[3].version, "4.0.0");
assert.equal(bundled[3].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(bundled[3].fieldContracts.signal_state, {
  type: "string",
  required: true,
  enum: ["active", "inactive"],
});
assert.deepEqual(bundled[3].fieldContracts.movement_state, {
  type: "string",
  required: true,
  enum: ["moving", "stopped"],
});
assert.equal(bundled[4].version, "5.0.0");
assert.equal(bundled[4].ontologyRevision, "ontology.map.moving_object.v3");
assert.equal(bundled[4].fieldContracts.sensor_readings.type, "telemetry_readings");
assert.equal(bundled[5].version, "1.0.0");
assert.equal(bundled[5].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(bundled[5].semanticTypes, ["map.moving_object"]);
assert.equal(bundled[5].history.mode, "none");
assert.equal(bundled[5].fieldContracts.device_phone_primary.type, "string");
assert.equal(bundled[6].version, "2.0.0");
assert.equal(bundled[6].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(bundled[6].semanticTypes, ["map.moving_object"]);
assert.equal(bundled[6].history.mode, "none");
assert.equal(bundled[6].fieldContracts.available_user_emails.type, "string_array");
assert.equal(bundled[6].fieldContracts.provider_creator_email.type, "string");
assert.equal(bundled[7].version, "1.0.0");
assert.equal(bundled[7].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(bundled[7].semanticTypes, ["map.moving_object"]);
assert.equal(bundled[7].history.mode, "none");
assert.equal(bundled[7].fieldContracts.available_user_logins.type, "string_array");
assert.equal(bundled[7].fieldContracts.device_imei.type, "string");
assert.equal(bundled[8].version, "1.0.0");
assert.equal(bundled[8].ontologyRevision, "ontology.map.moving_object.v3");
assert.deepEqual(bundled[8].semanticTypes, ["map.moving_object"]);
assert.equal(bundled[8].history.mode, "none");
assert.equal(bundled[8].fieldContracts.hardware_port.type, "number");
assert.equal(bundled[9].version, "1.0.0");
assert.equal(bundled[9].ontologyRevision, "ontology.map.zone.v1");
assert.deepEqual(bundled[9].semanticTypes, ["map.zone"]);
assert.deepEqual(bundled[9].fieldContracts.geometry, { type: "geometry", required: true });
assert.equal(bundled[9].fields.includes("dataset_authority"), false);
assert.equal(bundled[10].version, "2.0.0");
assert.equal(bundled[10].ontologyRevision, "ontology.map.zone.v1");
assert.deepEqual(bundled[10].semanticTypes, ["map.zone"]);
assert.deepEqual(bundled[10].fieldContracts.geometry, { type: "geometry", required: true });
assert.deepEqual(bundled[10].fieldContracts.dataset_authority.enum, ["moscow-department-of-transport"]);
assert.equal(Object.keys(bundled[3].fieldContracts).length, bundled[3].fields.length);
assert.equal(Object.keys(bundled[4].fieldContracts).length, bundled[4].fields.length);
assert.equal(Object.keys(bundled[5].fieldContracts).length, bundled[5].fields.length);
assert.equal(Object.keys(bundled[6].fieldContracts).length, bundled[6].fields.length);
assert.equal(Object.keys(bundled[7].fieldContracts).length, bundled[7].fields.length);
assert.equal(Object.keys(bundled[8].fieldContracts).length, bundled[8].fields.length);
assert.equal(Object.keys(bundled[9].fieldContracts).length, bundled[9].fields.length);
assert.equal(Object.keys(bundled[10].fieldContracts).length, bundled[10].fields.length);

const directory = await mkdtemp(join(tmpdir(), "nodedc-edp-definitions-"));
try {
  await writeFile(join(directory, "wrong-name.json"), JSON.stringify({
    ...bundled[0],
    id: "another.product.v1",
  }));
  await assert.rejects(loadDataProductDefinitions(directory), /data_product_definition_filename_mismatch/);
  await mkdir(join(directory, "ignored.json"));
  await assert.rejects(loadDataProductDefinitions(directory), /data_product_definition_file_invalid/);
} finally {
  await rm(directory, { recursive: true, force: true });
}

console.log("external-data-plane definitions: ok");
