import { geliosProviderPackageV5 } from "../v5/package.mjs";

export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v6";
export const GELIOS_PROVIDER_PACKAGE_VERSION = "6.0.0";
export const GELIOS_ZONES_DATA_PRODUCT_ID = "map.gelios-geofences.current.v1";
export const GELIOS_ZONES_DATA_PRODUCT_VERSION = "1.0.0";
export const GELIOS_ZONES_ONTOLOGY_REVISION = "ontology.map.zone.v1";
export const GELIOS_ZONE_SOURCE_ID_PREFIX = "gelios-zone-";

const ZONES_CAPABILITY_ID = "gelios.geozones.current.read";
const ZONES_FIELD_POLICY_ID = "gelios.geozones.current.fields.v1";
const ZONES_PROFILE_ID = "gelios.geozones.current.realtime.v1";
const ZONES_MAPPING_ID = "gelios.geozones.to.map.gelios-geofences.current.v1";
const ZONES_TEMPLATE_ID = "gelios.geozones.current.l2.v1";

const value = structuredClone(geliosProviderPackageV5);
const authModeId = value.authModes[0].id;
const zonesFields = [
  "area_square_meters",
  "description",
  "display_name",
  "geometry",
  "geometry_kind",
  "max_speed_kph",
  "perimeter_meters",
  "source_kind",
  "source_revision",
  "style_color",
];

value.id = GELIOS_PROVIDER_PACKAGE_ID;
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
value.manifest = {
  ...value.manifest,
  id: "gelios.provider.manifest.v6",
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  capabilityIds: [...value.manifest.capabilityIds, ZONES_CAPABILITY_ID],
  fieldPolicyIds: [...value.manifest.fieldPolicyIds, ZONES_FIELD_POLICY_ID],
  collectionProfileIds: [...value.manifest.collectionProfileIds, ZONES_PROFILE_ID],
  dataProductIds: [...value.manifest.dataProductIds, GELIOS_ZONES_DATA_PRODUCT_ID],
  mappingContractIds: [...value.manifest.mappingContractIds, ZONES_MAPPING_ID],
  l2TemplateIds: [...value.manifest.l2TemplateIds, ZONES_TEMPLATE_ID],
};
value.capabilities.push({
  id: ZONES_CAPABILITY_ID,
  classification: "read",
  status: "implemented",
  authModeId,
  request: {
    method: "GET",
    baseUrl: "https://api.geliospro.com",
    path: "/api/v1/geozones",
    query: { pl: 100, po: 0 },
    response: {
      collectionPaths: ["items"],
      pagination: {
        mode: "offset",
        limitParameter: "pl",
        offsetParameter: "po",
        pageSize: 100,
        itemsPath: "items",
        totalPath: "paginationMetadata.totalCount",
        maxPages: 50,
        maxItems: 5000,
        maxResponseBytes: 16 * 1024 * 1024,
      },
    },
  },
  entityScope: {
    mode: "all_visible_to_credential",
    refresh: "each_collection_run",
    businessEntityFilter: "forbidden",
  },
});
value.fieldPolicies.push({
  id: ZONES_FIELD_POLICY_ID,
  version: GELIOS_ZONES_DATA_PRODUCT_VERSION,
  dataProductId: GELIOS_ZONES_DATA_PRODUCT_ID,
  targetFields: [...zonesFields],
  unknownSourceFields: "drop",
  dynamicSourceFields: "drop_until_classified",
  restrictedSourcePaths: ["accessToken", "authorization", "refreshToken", "userToken"],
});
value.collectionProfiles.push({
  id: ZONES_PROFILE_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  mode: "realtime",
  schedule: { intervalMs: 3_600_000 },
  capabilityIds: [ZONES_CAPABILITY_ID],
  dataProductId: GELIOS_ZONES_DATA_PRODUCT_ID,
  mappingContractId: ZONES_MAPPING_ID,
  fieldPolicyId: ZONES_FIELD_POLICY_ID,
  l2TemplateId: ZONES_TEMPLATE_ID,
  entityScope: {
    mode: "all_visible_to_credential",
    refresh: "each_collection_run",
    businessEntityFilter: "forbidden",
  },
  batching: { maxFacts: 5000 },
  cardinality: { maxCurrentEntities: 5000, onExceed: "require_partitioned_data_product" },
  retry: { maxAttempts: 4, backoff: "exponential_with_jitter" },
});
value.dataProducts.push({
  id: GELIOS_ZONES_DATA_PRODUCT_ID,
  version: GELIOS_ZONES_DATA_PRODUCT_VERSION,
  ontologyRevision: GELIOS_ZONES_ONTOLOGY_REVISION,
  deliveryMode: "snapshot+patch",
  semanticTypes: ["map.zone"],
  fields: [...zonesFields],
  fieldContracts: {
    area_square_meters: { type: "number", required: false, minimum: 0 },
    description: { type: "string", required: false },
    display_name: { type: "string", required: true },
    geometry: { type: "geometry", required: true },
    geometry_kind: { type: "string", required: true, enum: ["circle", "corridor", "polygon"] },
    max_speed_kph: { type: "number", required: false, minimum: 0 },
    perimeter_meters: { type: "number", required: false, minimum: 0 },
    source_kind: { type: "string", required: true, enum: ["live_api", "versioned_snapshot"] },
    source_revision: { type: "string", required: true },
    style_color: { type: "string", required: false },
  },
  history: { mode: "none", retentionDays: 1 },
});
value.mappingContracts.push({
  schemaVersion: "nodedc.semantic-mapping/v1",
  id: ZONES_MAPPING_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  sourceCapabilityId: ZONES_CAPABILITY_ID,
  fieldPolicyId: ZONES_FIELD_POLICY_ID,
  target: {
    dataProductId: GELIOS_ZONES_DATA_PRODUCT_ID,
    version: GELIOS_ZONES_DATA_PRODUCT_VERSION,
    ontologyRevision: GELIOS_ZONES_ONTOLOGY_REVISION,
    semanticType: "map.zone",
  },
  derivations: {
    geometry_kind: {
      kind: "ordered_rules",
      rules: ["type_circle.circle", "type_line.corridor", "otherwise.polygon"],
      default: "polygon",
    },
  },
  fact: {
    sourceId: { strategy: "first_non_empty", paths: ["id"], coerce: "string", prefix: GELIOS_ZONE_SOURCE_ID_PREFIX },
    semanticType: { constant: "map.zone" },
    observedAt: { strategy: "first_non_empty", paths: ["updatedAt"], coerce: "unix_or_iso_timestamp", fallback: "collection_received_at" },
    geometry: {
      type: "GeoJSON",
      strategy: "bounded_zone_geometry_v1",
      kindPath: "type",
      polygonPointsPath: "points",
      corridorPointsPath: "line",
      radiusPath: "radius",
      coordinateOrder: "latitude_longitude",
      circleSegments: 64,
      allowedTypes: ["Polygon", "MultiPolygon"],
      omitIfInvalid: false,
    },
    attributes: {
      area_square_meters: { strategy: "first_non_empty", paths: ["surfaceArea", "surface_area"], coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true },
      description: { strategy: "first_non_empty", paths: ["description", "descr"], coerce: "string", omitIfMissing: true },
      display_name: { strategy: "first_non_empty", paths: ["name"], coerce: "string" },
      geometry_kind: { derive: "geometry_kind" },
      max_speed_kph: { strategy: "first_non_empty", paths: ["maxPermissibleSpeed", "max_permissible_speed"], coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true },
      perimeter_meters: { strategy: "first_non_empty", paths: ["perimeter"], coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true },
      source_kind: { constant: "live_api" },
      source_revision: { constant: "gelios-rest-v1" },
      style_color: { strategy: "first_non_empty", paths: ["color"], coerce: "string", omitIfMissing: true },
    },
  },
});
value.l2Templates.push({
  schemaVersion: "nodedc.l2-template/v1",
  id: ZONES_TEMPLATE_ID,
  version: GELIOS_PROVIDER_PACKAGE_VERSION,
  runtime: "ndc_l2",
  instanceMode: "one_connection_per_workflow",
  connectionParameters: ["tenant_id", "connection_id", "collection_profile_id", "provider_credential_ref"],
  credentialBindings: structuredClone(value.l2Templates[0].credentialBindings),
  steps: [
    { id: "collection.trigger", kind: "collection_trigger", collectionProfileDriven: true },
    { id: "provider.fetch-geozones", kind: "provider_request", capabilityId: ZONES_CAPABILITY_ID },
    { id: "provider.extract-geozones", kind: "extract_items", capabilityId: ZONES_CAPABILITY_ID },
    { id: "ontology.map", kind: "semantic_mapping", mappingContractId: ZONES_MAPPING_ID },
    { id: "data-product.publish", kind: "data_product_publish", dataProductId: GELIOS_ZONES_DATA_PRODUCT_ID, nodeType: "n8n-nodes-ndc.ndcDataProductPublish" },
  ],
  invariants: structuredClone(value.l2Templates[0].invariants),
});

export const geliosProviderPackageV6 = 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;
}
