import { geliosProviderPackageV4 } from "../v4/package.mjs";

export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v5";
export const GELIOS_PROVIDER_PACKAGE_VERSION = "5.0.0";
export const GELIOS_POSITIONS_DATA_PRODUCT_ID = "fleet.positions.current.v4";
export const GELIOS_POSITIONS_DATA_PRODUCT_VERSION = "4.0.0";
export const GELIOS_POSITIONS_ONTOLOGY_REVISION = "ontology.map.moving_object.v3";
export const GELIOS_UNIT_SOURCE_ID_PREFIX = "gelios-unit-";

const FIELD_POLICY_ID = "gelios.positions.current.fields.v4";
const REALTIME_PROFILE_ID = "gelios.positions.current.realtime.v5";
const MANUAL_PROFILE_ID = "gelios.positions.current.manual.v5";
const MAPPING_ID = "gelios.units.to.fleet.positions.current.v5";
const TEMPLATE_ID = "gelios.positions.current.l2.v5";

const value = structuredClone(geliosProviderPackageV4);
const dataProduct = {
  id: GELIOS_POSITIONS_DATA_PRODUCT_ID,
  version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
  ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION,
  deliveryMode: "snapshot+patch",
  semanticTypes: ["map.moving_object"],
  fields: [...value.dataProducts[0].fields],
  fieldContracts: {
    course_degrees: { type: "number", required: false, minimum: 0, maximum: 360 },
    display_name: { type: "string", required: true },
    elevation_meters: { type: "number", required: false },
    geometry: { type: "point", required: false },
    hdop: { type: "number", required: false, minimum: 0 },
    horizontal_accuracy_meters: { type: "number", required: false, minimum: 0 },
    movement_state: { type: "string", required: true, enum: ["moving", "stopped"] },
    object_kind: { type: "string", required: true },
    position_source: { type: "string", required: true },
    satellite_count: { type: "number", required: false, minimum: 0 },
    signal_state: { type: "string", required: true, enum: ["active", "inactive"] },
    speed_kph: { type: "number", required: false, minimum: 0 },
  },
  history: { ...value.dataProducts[0].history },
};

value.id = GELIOS_PROVIDER_PACKAGE_ID;
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
value.manifest = {
  ...value.manifest,
  id: "gelios.provider.manifest.v5",
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  fieldPolicyIds: [FIELD_POLICY_ID],
  collectionProfileIds: [REALTIME_PROFILE_ID, MANUAL_PROFILE_ID],
  dataProductIds: [GELIOS_POSITIONS_DATA_PRODUCT_ID],
  mappingContractIds: [MAPPING_ID],
  l2TemplateIds: [TEMPLATE_ID],
};
value.fieldPolicies = value.fieldPolicies.map((policy) => ({
  ...policy,
  id: FIELD_POLICY_ID,
  version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
  dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
}));
value.collectionProfiles = value.collectionProfiles.map((profile, index) => ({
  ...profile,
  id: index === 0 ? REALTIME_PROFILE_ID : MANUAL_PROFILE_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
  mappingContractId: MAPPING_ID,
  fieldPolicyId: FIELD_POLICY_ID,
  l2TemplateId: TEMPLATE_ID,
}));
value.dataProducts = [dataProduct];
value.mappingContracts = value.mappingContracts.map((mapping) => ({
  ...mapping,
  id: MAPPING_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  fieldPolicyId: FIELD_POLICY_ID,
  target: {
    ...mapping.target,
    dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
    version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
    ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION,
  },
}));
const attributes = value.mappingContracts[0].fact.attributes;
Object.assign(attributes.course_degrees, { minimum: 0, maximum: 360, omitIfInvalid: true });
Object.assign(attributes.hdop, { minimum: 0, omitIfInvalid: true });
Object.assign(attributes.horizontal_accuracy_meters, { minimum: 0, omitIfInvalid: true });
Object.assign(attributes.satellite_count, { minimum: 0, omitIfInvalid: true });
Object.assign(attributes.speed_kph, { minimum: 0, omitIfInvalid: true });
value.l2Templates = value.l2Templates.map((template) => ({
  ...template,
  id: TEMPLATE_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  steps: template.steps.map((step) => {
    if (step.kind === "semantic_mapping") return { ...step, mappingContractId: MAPPING_ID };
    if (step.kind === "data_product_publish") return { ...step, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID };
    return step;
  }),
}));

export const geliosProviderPackageV5 = deepFreeze(value);

function deepFreeze(input) {
  if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
  Object.freeze(input);
  for (const child of Object.values(input)) deepFreeze(child);
  return input;
}
