import { geliosProviderPackageV1 } from "../v1/package.mjs";

export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v3";
export const GELIOS_PROVIDER_PACKAGE_VERSION = "3.0.0";
export const GELIOS_POSITIONS_DATA_PRODUCT_ID = "fleet.positions.current.v2";
export const GELIOS_POSITIONS_DATA_PRODUCT_VERSION = "2.0.0";
export const GELIOS_POSITIONS_ONTOLOGY_REVISION = "ontology.map.moving_object.v2";
export const GELIOS_UNIT_SOURCE_ID_PREFIX = "gelios-unit-";

const FIELD_POLICY_ID = "gelios.positions.current.fields.v2";
const AUTH_MODE_ID = "gelios.rest-rotating-bearer.v3";
const REALTIME_PROFILE_ID = "gelios.positions.current.realtime.v3";
const MANUAL_PROFILE_ID = "gelios.positions.current.manual.v3";
const MAPPING_ID = "gelios.units.to.fleet.positions.current.v3";
const TEMPLATE_ID = "gelios.positions.current.l2.v3";
const STATE_POLICY_VERSION = "map-moving-object-state/v1";

const targetFields = Object.freeze([
  "availability_state",
  "course_degrees",
  "display_name",
  "elevation_meters",
  "freshness_state",
  "geometry",
  "hdop",
  "horizontal_accuracy_meters",
  "motion_state",
  "object_kind",
  "operational_status",
  "position_source",
  "position_state",
  "position_valid",
  "quality_flags",
  "satellite_count",
  "speed_kph",
  "state_policy_version",
]);

const value = structuredClone(geliosProviderPackageV1);
value.id = GELIOS_PROVIDER_PACKAGE_ID;
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
value.manifest = {
  ...value.manifest,
  id: "gelios.provider.manifest.v3",
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  authModeIds: [AUTH_MODE_ID],
  fieldPolicyIds: [FIELD_POLICY_ID],
  collectionProfileIds: [REALTIME_PROFILE_ID, MANUAL_PROFILE_ID],
  dataProductIds: [GELIOS_POSITIONS_DATA_PRODUCT_ID],
  mappingContractIds: [MAPPING_ID],
  l2TemplateIds: [TEMPLATE_ID],
};
value.authModes = [{
  ...value.authModes[0],
  id: AUTH_MODE_ID,
  tokenLifecycle: {
    artifacts: ["access", "refresh"],
    requestArtifact: "access",
    refreshMode: "runtime_managed",
  },
}];
value.capabilities = [{
  ...value.capabilities[0],
  authModeId: AUTH_MODE_ID,
}];
value.fieldPolicies = [{
  ...value.fieldPolicies[0],
  id: FIELD_POLICY_ID,
  version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
  dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
  targetFields: [...targetFields],
}];
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 = [{
  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: [...targetFields],
  history: {
    mode: "sampled",
    intervalMs: 60000,
    strategy: "latest-per-entity-per-bucket",
    retentionDays: 90,
  },
}];
value.mappingContracts = [{
  ...value.mappingContracts[0],
  id: MAPPING_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  fieldPolicyId: FIELD_POLICY_ID,
  target: {
    ...value.mappingContracts[0].target,
    dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
    version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
    ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION,
  },
  derivations: {
    ...value.mappingContracts[0].derivations,
    availability_state: {
      kind: "ordered_rules",
      rules: [
        "observed_age_gt_limit.offline",
        "otherwise.online",
      ],
      default: "unknown",
      parameters: { staleAfterMs: 60000 },
    },
    freshness_state: {
      kind: "ordered_rules",
      rules: [
        "observed_age_gt_limit.stale",
        "otherwise.fresh",
      ],
      default: "stale",
      parameters: { staleAfterMs: 60000 },
    },
    motion_state: {
      kind: "ordered_rules",
      rules: [
        "speed_kph_gte_threshold.moving",
        "speed_kph_lt_threshold.stationary",
        "otherwise.unknown",
      ],
      default: "unknown",
      parameters: { movingThresholdKph: 1 },
    },
    position_state: {
      kind: "ordered_rules",
      rules: [
        "position_invalid.missing",
        "position_quality_below_threshold.low_quality",
        "otherwise.valid",
      ],
      default: "missing",
      parameters: {
        minSatelliteCount: 4,
        maxHdop: 5,
        maxHorizontalAccuracyMeters: 100,
      },
    },
  },
  fact: {
    ...value.mappingContracts[0].fact,
    attributes: {
      ...value.mappingContracts[0].fact.attributes,
      availability_state: { derive: "availability_state" },
      freshness_state: { derive: "freshness_state" },
      motion_state: { derive: "motion_state" },
      position_state: { derive: "position_state" },
      state_policy_version: { constant: STATE_POLICY_VERSION },
    },
  },
}];
value.l2Templates = [{
  ...value.l2Templates[0],
  id: TEMPLATE_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  credentialBindings: value.l2Templates[0].credentialBindings.map((binding) => (
    binding.role === "provider" ? { ...binding, authModeId: AUTH_MODE_ID } : binding
  )),
  steps: value.l2Templates[0].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 geliosProviderPackageV3 = 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;
}
