import * as fs from 'node:fs';
import * as path from 'node:path';

import { RequestReply } from '@open-matrix/core/engine/remoting/RequestReply.js';
import type { MatrixActor } from '@open-matrix/core/core/MatrixActor.js';
import { MatrixRuntime } from '@open-matrix/core/runtime/MatrixRuntime.js';
import {
  countRuntimeDirectory,
  publishRuntimePresence,
} from '@open-matrix/core';
import type {
  MatrixMountCardinality,
  MatrixPlacementClaimMode,
  RuntimeInventoryPlacementMetadata,
} from '@open-matrix/contracts/placement';
import type { RuntimePresenceRecordV1 } from '@open-matrix/contracts/runtime-presence';
import type { ILoadedMatrixPackageEnvironment } from './package-environment.js';
import type { IResolvedRunnerTransportPlan } from './runner-transport.js';
import type {
  ILoadedMatrixBindingDeclaration,
  ILoadedMatrixServiceManifest,
} from './service-manifest.js';
import { readRunnerPlacementStandbyResults } from './runner-placement-policy.js';
import { BindingsRegistryActor } from '@open-matrix/system-bindings';
import { ServiceRegistryActor } from '@open-matrix/system-platform';
import { RuntimeManagerActor } from '@open-matrix/system-runtimes';

const RUNTIME_REGISTRY_MOUNT = 'system.runtimes';
const LOGICAL_REGISTRY_MOUNT = 'system.registry';
const BINDINGS_REGISTRY_MOUNT = 'system.bindings';
const RUNTIME_PRESENCE_TTL_MS = 30_000;
const LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS = 5_000;
const LINKED_CONTROL_PLANE_REQUEST_TIMEOUT_MS = 15_000;

interface IRuntimeInventoryEntry {
  readonly mount: string;
  readonly type?: string;
  readonly runtimeId: string;
  readonly claimKind: MatrixPlacementClaimMode;
  readonly placement: RuntimeInventoryPlacementMetadata;
  readonly description?: string;
  readonly hasChildren?: boolean;
}

interface IPlacementDeclarationIndex {
  readonly byMount: ReadonlyMap<string, MatrixMountCardinality>;
}

export interface IRunnerControlPlaneState {
  readonly runtimeRegistryMount: string;
  readonly logicalRegistryMount: string;
  readonly bindingsRegistryMount: string;
  readonly createdRuntimeRegistry: boolean;
  readonly createdLogicalRegistry: boolean;
  readonly createdBindingsRegistry: boolean;
}

export interface IRunnerRuntimeRegistration {
  readonly runtimeId: string;
  readonly runtimeRoot: string;
  readonly presence: RuntimePresenceRecordV1;
  readonly registryMount: string;
  readonly logicalRegistryMount: string;
  readonly controlTargetRoot?: string;
  readonly protocolRequest?: boolean;
  readonly runtimeMount?: string;
  readonly controlMount?: string;
  readonly created: boolean;
  readonly actorCount: number;
  readonly inventoryClaimCount: number;
  readonly runtimeCount: number;
  readonly registryOptional?: boolean;
  /**
   * Re-issue the inventory `registry.claim` calls and re-publish presence.
   * Used by the heartbeat tick when `registry.claim.renew` reports the
   * registry no longer has our claim (e.g. after the registry actor's
   * in-memory `_claims` map was wiped by a SYSTEM runtime restart).
   * Idempotent: `onRegistryClaim` preserves `registeredAt`/`claimedAt`
   * when an existing entry is found.
   */
  readonly reclaim: () => Promise<{ inventoryClaimCount: number }>;
}

export interface IRunnerRuntimeDeregistration {
  readonly runtimeId: string;
  readonly registryMount: string;
  readonly removed: boolean;
  readonly runtimeCount: number;
}

export interface IRunnerRuntimeHeartbeat {
  readonly runtimeId: string;
  readonly known: boolean;
}

export interface IRunnerWebappRouteMetadata {
  readonly appName: string;
  readonly routePrefix?: string;
  readonly displayName?: string;
  readonly icon?: string;
  readonly navOrder?: number;
  readonly description?: string;
  readonly shells?: readonly string[];
  readonly assetMount?: string;
  readonly origin?: string;
  readonly port?: number;
}

export interface IRunnerBindingRegistration {
  readonly runtimeId: string;
  readonly registryMount: string;
  readonly logicalRegistryMount: string;
  readonly controlTargetRoot?: string;
  readonly protocolRequest?: boolean;
  readonly registeredCount: number;
  readonly registryClaimCount: number;
  readonly registryOptional?: boolean;
  readonly bindings: ReadonlyArray<{
    readonly binding: string;
    readonly localMount: string;
    readonly ops: readonly string[];
    readonly packageName: string;
  }>;
  /**
   * Re-issue every server-side record this runner published at registration
   * time: the canonical-binding `registry.claim` calls AND the
   * `bindings.register` calls. Both are in-memory on their respective
   * registry actors, so a single SYSTEM restart wipes them together. The
   * heartbeat tick triggers reclaim when `registry.claim.renew` reports the
   * registry no longer has our claims; bindings.register loss is treated as
   * a co-occurring symptom of the same SYSTEM restart and reclaimed in
   * lockstep. Both server-side ops are idempotent (onRegistryClaim
   * preserves identity; bindings.register is keyed by provider+match), so
   * calling reclaim() against a healthy registry is harmless.
   */
  readonly reclaim: () => Promise<{
    readonly registryClaimCount: number;
    readonly bindingsRegisteredCount: number;
  }>;
}

export interface IRunnerBindingDeregistration {
  readonly runtimeId: string;
  readonly registryMount: string;
  readonly logicalRegistryMount: string;
  readonly removedCount: number;
  readonly registryRemovedCount: number;
}

export interface IRunnerBindingRenewal {
  readonly runtimeId: string;
  readonly refreshed: number;
}

interface ICanonicalBindingDefinition {
  readonly binding: string;
  readonly localMount: string;
  readonly ops: readonly string[];
  readonly packageName: string;
}

interface IRunnerHostPlacement {
  readonly deviceId: string;
  readonly hostId: string;
  readonly hostName?: string;
  readonly deviceSlug?: string;
}

interface IControlPlaneRequestOptions {
  readonly timeoutMs: number;
  readonly targetRoot?: string;
  readonly protocolRequest?: boolean;
}

export async function ensureRunnerControlPlane(runtime: MatrixRuntime): Promise<IRunnerControlPlaneState> {
  const createdRuntimeRegistry = await ensureRegistryActor(runtime, RUNTIME_REGISTRY_MOUNT, RuntimeManagerActor);
  const createdLogicalRegistry = await ensureRegistryActor(runtime, LOGICAL_REGISTRY_MOUNT, ServiceRegistryActor);
  const createdBindingsRegistry = await ensureRegistryActor(runtime, BINDINGS_REGISTRY_MOUNT, BindingsRegistryActor);
  return {
    runtimeRegistryMount: RUNTIME_REGISTRY_MOUNT,
    logicalRegistryMount: LOGICAL_REGISTRY_MOUNT,
    bindingsRegistryMount: BINDINGS_REGISTRY_MOUNT,
    createdRuntimeRegistry,
    createdLogicalRegistry,
    createdBindingsRegistry,
  };
}

export interface IEnsureRunnerControlPlaneOptions {
  readonly createLocalRegistries?: boolean;
}

export async function ensureRunnerControlPlaneForMode(
  runtime: MatrixRuntime,
  options: IEnsureRunnerControlPlaneOptions = {},
): Promise<IRunnerControlPlaneState> {
  const createLocalRegistries = options.createLocalRegistries ?? true;
  const createdRuntimeRegistry = createLocalRegistries
    ? await ensureRegistryActor(runtime, RUNTIME_REGISTRY_MOUNT, RuntimeManagerActor)
    : false;
  const createdLogicalRegistry = createLocalRegistries
    ? await ensureRegistryActor(runtime, LOGICAL_REGISTRY_MOUNT, ServiceRegistryActor)
    : false;
  const createdBindingsRegistry = createLocalRegistries
    ? await ensureRegistryActor(runtime, BINDINGS_REGISTRY_MOUNT, BindingsRegistryActor)
    : false;
  return {
    runtimeRegistryMount: RUNTIME_REGISTRY_MOUNT,
    logicalRegistryMount: LOGICAL_REGISTRY_MOUNT,
    bindingsRegistryMount: BINDINGS_REGISTRY_MOUNT,
    createdRuntimeRegistry,
    createdLogicalRegistry,
    createdBindingsRegistry,
  };
}

export async function registerRunnerRuntime(
  runtime: MatrixRuntime,
  manifest: ILoadedMatrixServiceManifest,
  environment: ILoadedMatrixPackageEnvironment | undefined,
  runnerTransport: IResolvedRunnerTransportPlan | undefined,
  serviceMount?: string,
  runtimeMount?: string,
  controlMount?: string,
  webappRoute?: IRunnerWebappRouteMetadata,
): Promise<IRunnerRuntimeRegistration> {
  const controlPlane = await ensureRunnerControlPlaneForMode(runtime, {
    createLocalRegistries: !isHostManagedEnvironment(environment),
  });
  const runtimeId = resolveRunnerRuntimeId(manifest, environment);
  const runtimeRoot = readTransportRoot(runtime)
    ?? environment?.environment.runtime.root
    ?? manifest.root
    ?? runtimeId;
  const hostPlacement = resolveRunnerHostPlacement(runtime, environment);
  const registryOptional = isHostedAuthorityLeafEnvironment(runtime, environment);
  const actorCount = runtime.getAllComponents().length;
  const placementDeclarations = readPlacementDeclarations(manifest);
  const requestOptions = controlPlaneRequestOptions(
    runtime,
    environment,
    controlPlaneRequestTimeoutMs(environment),
  );
  const inventory = buildRuntimeInventory(runtime, runtimeId, placementDeclarations);
  const presence = buildRuntimePresenceRecord({
    runtimeId,
    runtimeRoot,
    manifest,
    environment,
    actorCount,
    inventory,
    serviceMount,
    runtimeMount,
    controlMount,
    runnerTransport,
    webappRoute,
    hostPlacement,
  });
  const inventoryClaimCount = await registerRuntimeInventoryClaims(
    runtime,
    controlPlane.logicalRegistryMount,
    manifest,
    environment,
    runtimeId,
    runtimeRoot,
    inventory,
    serviceMount,
    webappRoute,
    hostPlacement,
    registryOptional,
  );

  publishRuntimePresence(runtime.getRootContext(), presence, 'announce');
  const runtimeCount = await tryReadRegisteredRuntimeCount(
    runtime,
    controlPlane.logicalRegistryMount,
  );

  // Closure for re-issuing the same inventory claims when the registry has
  // forgotten us (renew returns renewed: 0). Captures everything needed —
  // the runtime, the original manifest/environment, runtimeId, etc. —
  // so the heartbeat tick can call reclaim() without re-resolving any
  // identity. `onRegistryClaim` is idempotent for an existing entry, so
  // calling reclaim() when the registry IS healthy is harmless.
  const reclaim = async (): Promise<{ inventoryClaimCount: number }> => {
    const freshActorCount = runtime.getAllComponents().length;
    const freshInventory = buildRuntimeInventory(runtime, runtimeId, placementDeclarations);
    const freshPresence = buildRuntimePresenceRecord({
      runtimeId,
      runtimeRoot,
      manifest,
      environment,
      actorCount: freshActorCount,
      inventory: freshInventory,
      serviceMount,
      runtimeMount,
      controlMount,
      runnerTransport,
      webappRoute,
      hostPlacement,
    });
    const reclaimedCount = await registerRuntimeInventoryClaims(
      runtime,
      controlPlane.logicalRegistryMount,
      manifest,
      environment,
      runtimeId,
      runtimeRoot,
      freshInventory,
      serviceMount,
      webappRoute,
      hostPlacement,
      registryOptional,
    );
    // Re-announce presence so RuntimeManagerActor's _runtimes Map repopulates
    // with us even if it was cleared by a SYSTEM restart.
    publishRuntimePresence(runtime.getRootContext(), freshPresence, 'announce');
    return { inventoryClaimCount: reclaimedCount };
  };

  return {
    runtimeId,
    runtimeRoot,
    presence,
    registryMount: controlPlane.runtimeRegistryMount,
    logicalRegistryMount: controlPlane.logicalRegistryMount,
    ...(requestOptions.targetRoot ? { controlTargetRoot: requestOptions.targetRoot } : {}),
    ...(requestOptions.protocolRequest === true ? { protocolRequest: true } : {}),
    ...(runtimeMount ? { runtimeMount } : {}),
    ...(controlMount ? { controlMount } : {}),
    created: true,
    actorCount,
    inventoryClaimCount,
    runtimeCount,
    ...(registryOptional ? { registryOptional: true } : {}),
    reclaim,
  };
}

export async function deregisterRunnerRuntime(
  runtime: MatrixRuntime,
  registration: IRunnerRuntimeRegistration | undefined,
): Promise<IRunnerRuntimeDeregistration | undefined> {
  if (!registration) {
    return undefined;
  }
  if (registration.registryOptional === true) {
    const departedAt = Date.now();
    publishRuntimePresence(
      runtime.getRootContext(),
      {
        ...registration.presence,
        lastHeartbeat: departedAt,
        health: {
          status: 'stopped',
          updatedAt: departedAt,
        },
      },
      'departed',
    );
    return {
      runtimeId: registration.runtimeId,
      registryMount: registration.registryMount,
      removed: false,
      runtimeCount: 0,
    };
  }

  const registryReleased = await RequestReply.execute<Record<string, unknown>, { removed?: number }>(
    runtime.getRootContext(),
    registration.logicalRegistryMount,
    'registry.release',
    { providerRuntimeId: registration.runtimeId },
    registrationControlPlaneRequestOptions(registration, LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS),
  );
  const departedAt = Date.now();
  publishRuntimePresence(
    runtime.getRootContext(),
    {
      ...registration.presence,
      lastHeartbeat: departedAt,
      health: {
        status: 'stopped',
        updatedAt: departedAt,
      },
    },
    'departed',
  );

  const runtimeCount = await tryReadRegisteredRuntimeCount(
    runtime,
    registration.logicalRegistryMount,
  );

  return {
    runtimeId: registration.runtimeId,
    registryMount: registration.registryMount,
    removed: typeof registryReleased.removed === 'number' && registryReleased.removed > 0,
    runtimeCount,
  };
}

async function tryReadRegisteredRuntimeCount(
  runtime: MatrixRuntime,
  _registryMount: string,
): Promise<number> {
  // Slice 1b (control-actor-nav): runtime directory authority is
  // `system.runtimes`, not the service registry. Read through the adapter.
  try {
    return await countRuntimeDirectory(runtime.getRootContext(), { includeStale: true });
  } catch {
    return 0;
  }
}

export async function heartbeatRunnerRuntime(
  runtime: MatrixRuntime,
  registration: IRunnerRuntimeRegistration | undefined,
): Promise<IRunnerRuntimeHeartbeat | undefined> {
  if (!registration) {
    return undefined;
  }
  if (registration.registryOptional === true) {
    const now = Date.now();
    publishRuntimePresence(
      runtime.getRootContext(),
      {
        ...registration.presence,
        inventory: rebuildRuntimeInventoryForHeartbeat(runtime, registration),
        lastHeartbeat: now,
        health: {
          status: registration.presence.health?.status ?? 'ok',
          ...(registration.presence.health?.reason ? { reason: registration.presence.health.reason } : {}),
          updatedAt: now,
        },
      },
      'heartbeat',
    );
    return {
      runtimeId: registration.runtimeId,
      known: true,
    };
  }
  const renewal = await RequestReply.execute<Record<string, unknown>, { renewed?: number }>(
    runtime.getRootContext(),
    registration.logicalRegistryMount,
    'registry.claim.renew',
    {
      providerRuntimeId: registration.runtimeId,
      ttlMs: 30_000,
    },
    registrationControlPlaneRequestOptions(registration, 5_000),
  );
  const now = Date.now();
  publishRuntimePresence(
    runtime.getRootContext(),
    {
      ...registration.presence,
      inventory: rebuildRuntimeInventoryForHeartbeat(runtime, registration),
      lastHeartbeat: now,
      health: {
        status: registration.presence.health?.status ?? 'ok',
        ...(registration.presence.health?.reason ? { reason: registration.presence.health.reason } : {}),
        updatedAt: now,
      },
    },
    'heartbeat',
  );
  return {
    runtimeId: registration.runtimeId,
    known: typeof renewal.renewed === 'number' && renewal.renewed > 0,
  };
}

export async function registerRunnerBindings(
  runtime: MatrixRuntime,
  manifest: ILoadedMatrixServiceManifest,
  environment: ILoadedMatrixPackageEnvironment | undefined,
  runtimeId: string,
  serviceMount?: string,
): Promise<IRunnerBindingRegistration> {
  const controlPlane = await ensureRunnerControlPlaneForMode(runtime, {
    createLocalRegistries: !isHostManagedEnvironment(environment),
  });
  const nonCallableBindingMounts = await resolveNonCallableBindingMounts(runtime, manifest, serviceMount);
  const bindings = deriveCanonicalBindings(manifest, environment, serviceMount)
    .filter((binding) => !nonCallableBindingMounts.has(binding.localMount));
  const placementDeclarations = readPlacementDeclarations(manifest);
  const runtimeWireRoot = readTransportRoot(runtime)
    ?? environment?.environment.runtime.root
    ?? manifest.root
    ?? runtimeId;
  const authorityRoot = environment?.environment.runtime.root
    ?? manifest.root
    ?? runtimeWireRoot;
  const hostPlacement = resolveRunnerHostPlacement(runtime, environment);
  const registryOptional = isHostedAuthorityLeafEnvironment(runtime, environment);
  const timeoutMs = controlPlaneRequestTimeoutMs(environment);
  const requestOptions = controlPlaneRequestOptions(runtime, environment, timeoutMs);
  const publishBindingForwards = shouldPublishBindingForwards(environment);

  const issueBindingClaims = async (): Promise<number> => {
    let issued = 0;
    for (const binding of bindings) {
      const placement = placementForMount(
        binding.localMount,
        binding.binding,
        resolveCardinalityForMount(placementDeclarations, binding.localMount),
        true,
      );
      await RequestReply.execute(
        runtime.getRootContext(),
        controlPlane.logicalRegistryMount,
        'registry.claim',
        {
          mount: binding.binding,
          kind: 'actor',
          componentId: `${binding.packageName}:${binding.binding}`,
          componentType: 'actor',
          authorityRoot,
          scope: 'identity-relative',
          providerRuntimeId: runtimeId,
          runtimeWireRoot,
          localMount: binding.localMount,
          packageName: binding.packageName,
          mode: placement.claimMode,
          cardinality: placement.cardinality,
          claimMode: placement.claimMode,
          logicalMount: placement.logicalMount,
          physicalMount: placement.physicalMount,
          callable: placement.callable,
          ...registryClaimPlacement(hostPlacement),
          metadata: {
            ops: [...binding.ops],
            source: 'runner-control-plane',
            placement,
            ...hostPlacementMetadata(hostPlacement),
          },
        },
        requestOptions,
      );
      issued += 1;
    }
    return issued;
  };

  const registerBindingForwards = async (): Promise<number> => {
    if (!publishBindingForwards) {
      return 0;
    }
    let registered = 0;
    for (const binding of bindings) {
      await RequestReply.execute(
        runtime.getRootContext(),
        controlPlane.bindingsRegistryMount,
        'bindings.register',
        {
          provider: runtimeId,
          runtimeId,
          packageName: binding.packageName,
          localMount: binding.localMount,
          match: binding.binding,
          ops: [...binding.ops],
          forward: binding.localMount,
        },
        requestOptions,
      );
      registered += 1;
    }
    return registered;
  };

  const registryClaimCount = registryOptional ? 0 : await issueBindingClaims();
  const bindingsRegisteredCount = registryOptional ? 0 : await registerBindingForwards();

  // Reclaim re-issues every server-side record this runner published at
  // registration time. Both registries (system.registry and system.bindings)
  // store their state in-memory. A single SYSTEM restart wipes them
  // together, so the heartbeat tick reclaims both in lockstep when
  // registry.claim.renew reports loss.
  const reclaim = async (): Promise<{
    registryClaimCount: number;
    bindingsRegisteredCount: number;
  }> => {
    const registryClaimCount = registryOptional ? 0 : await issueBindingClaims();
    const bindingsRegisteredCount = registryOptional ? 0 : await registerBindingForwards();
    return { registryClaimCount, bindingsRegisteredCount };
  };

  return {
    runtimeId,
    registryMount: controlPlane.bindingsRegistryMount,
    logicalRegistryMount: controlPlane.logicalRegistryMount,
    ...(requestOptions.targetRoot ? { controlTargetRoot: requestOptions.targetRoot } : {}),
    ...(requestOptions.protocolRequest === true ? { protocolRequest: true } : {}),
    registeredCount: bindingsRegisteredCount,
    registryClaimCount,
    ...(registryOptional ? { registryOptional: true } : {}),
    bindings,
    reclaim,
  };
}

export async function deregisterRunnerBindings(
  runtime: MatrixRuntime,
  registration: IRunnerBindingRegistration | undefined,
): Promise<IRunnerBindingDeregistration | undefined> {
  if (!registration) {
    return undefined;
  }
  if (registration.registeredCount === 0) {
    return {
      runtimeId: registration.runtimeId,
      registryMount: registration.registryMount,
      logicalRegistryMount: registration.logicalRegistryMount,
      removedCount: 0,
      registryRemovedCount: 0,
    };
  }

  const removed = await RequestReply.execute(
    runtime.getRootContext(),
    registration.registryMount,
    'bindings.remove',
    { provider: registration.runtimeId },
    registrationControlPlaneRequestOptions(registration, 5_000),
  ) as { removed?: number };

  return {
    runtimeId: registration.runtimeId,
    registryMount: registration.registryMount,
    logicalRegistryMount: registration.logicalRegistryMount,
    removedCount: typeof removed.removed === 'number' ? removed.removed : 0,
    registryRemovedCount: 0,
  };
}

export async function renewRunnerBindings(
  runtime: MatrixRuntime,
  registration: IRunnerBindingRegistration | undefined,
): Promise<IRunnerBindingRenewal | undefined> {
  if (!registration) {
    return undefined;
  }
  if (registration.registryOptional === true) {
    return {
      runtimeId: registration.runtimeId,
      refreshed: registration.bindings.length,
    };
  }
  const renewal = await RequestReply.execute(
    runtime.getRootContext(),
    registration.logicalRegistryMount,
    'registry.claim.renew',
    {
      packageName: registration.bindings[0]?.packageName,
      providerRuntimeId: registration.runtimeId,
    },
    registrationControlPlaneRequestOptions(registration, 5_000),
  ) as { renewed?: number };
  return {
    runtimeId: registration.runtimeId,
    refreshed: typeof renewal.renewed === 'number' ? renewal.renewed : 0,
  };
}

export function resolveRunnerRuntimeId(
  manifest: ILoadedMatrixServiceManifest,
  environment: ILoadedMatrixPackageEnvironment | undefined,
): string {
  const runtimeId = environment?.environment.runtime.runtimeId?.trim();
  if (runtimeId) {
    return runtimeId;
  }
  const manifestId = manifest.serviceInstance.id.trim();
  if (manifestId.length > 0) {
    return manifestId;
  }
  return manifest.packageName;
}

function isHostManagedEnvironment(environment: ILoadedMatrixPackageEnvironment | undefined): boolean {
  const matrixDir = environment?.environment.host?.matrixDir;
  return typeof matrixDir === 'string' && matrixDir.trim().length > 0;
}

function isHostedAuthorityLeafEnvironment(
  runtime: MatrixRuntime,
  environment: ILoadedMatrixPackageEnvironment | undefined,
): boolean {
  if (!isHostManagedEnvironment(environment)) {
    return false;
  }
  const topology = readRecord(runtime.getRootContext().getService<unknown>('matrix-node-topology'))
    ?? readRecord(environment?.environment.topology);
  const roles = readRecord(topology?.roles);
  const authorityCoordinator = readRecord(roles?.authorityCoordinator);
  if (authorityCoordinator?.active === false) {
    return true;
  }
  const hostHome = trimToUndefined(runtime.getRootContext().getService<unknown>('matrix-host-home'))
    ?? trimToUndefined(environment?.environment.host?.matrixDir);
  if (!hostHome) {
    return false;
  }
  const linkRecord = readJsonObjectIfPresent(path.join(hostHome, 'credentials', 'hivecast-link.json'));
  return linkRecord?.authorityCoordinator === false
    && Boolean(trimToUndefined(linkRecord.deviceRegistryRoot));
}

function readTransportRoot(runtime: MatrixRuntime): string | undefined {
  const root = (runtime.transport as { root?: unknown }).root;
  return typeof root === 'string' && root.trim().length > 0 ? root.trim() : undefined;
}

async function resolveNonCallableBindingMounts(
  runtime: MatrixRuntime,
  manifest: ILoadedMatrixServiceManifest,
  serviceMount: string | undefined,
): Promise<ReadonlySet<string>> {
  const mounts = new Set<string>();
  for (const standby of readRunnerPlacementStandbyResults(runtime)) {
    if (standby.placement.callable === false) {
      mounts.add(standby.mount);
    }
  }

  if (manifest.packageName === '@open-matrix/system') {
    const systemMount = serviceMount?.trim() || manifest.mount?.trim() || manifest.packageRoot?.mount?.trim() || 'system';
    const response = await RequestReply.execute<Record<string, unknown>, {
      readonly children?: readonly unknown[];
    }>(
      runtime.getRootContext(),
      systemMount,
      'system.children',
      {},
      { timeoutMs: 2_000 },
    );
    for (const child of response.children ?? []) {
      const record = isRecord(child) ? child : null;
      const mount = trimToUndefined(record?.mount);
      const status = trimToUndefined(record?.status);
      if (mount && status !== 'mounted') {
        mounts.add(mount);
      }
    }
  }

  return mounts;
}

function buildRuntimeInventory(
  runtime: MatrixRuntime,
  runtimeId: string,
  placementDeclarations: IPlacementDeclarationIndex,
): IRuntimeInventoryEntry[] {
  const inventory: IRuntimeInventoryEntry[] = [];
  for (const component of runtime.getAllComponents()) {
    const mount = component.mount.trim();
    if (mount.length === 0) {
      continue;
    }
    const placement = placementForMount(
      mount,
      mount,
      resolveCardinalityForMount(placementDeclarations, mount),
      true,
    );
    const description = typeof (component.constructor as { description?: unknown }).description === 'string'
      ? (component.constructor as { description?: string }).description
      : undefined;
    inventory.push({
      mount,
      ...(component.constructor.name ? { type: component.constructor.name } : {}),
      runtimeId,
      claimKind: placement.claimMode,
      placement,
      ...(description ? { description } : {}),
      ...(hasIntrospectChildren(component) ? { hasChildren: true } : {}),
    });
  }
  appendStandbyPlacementResults(inventory, runtime, runtimeId);
  return inventory;
}

function rebuildRuntimeInventoryForHeartbeat(
  runtime: MatrixRuntime,
  registration: IRunnerRuntimeRegistration,
): IRuntimeInventoryEntry[] {
  const previousPlacementByMount = new Map<string, RuntimeInventoryPlacementMetadata>();
  for (const entry of registration.presence.inventory ?? []) {
    if (entry.placement) {
      previousPlacementByMount.set(entry.mount, entry.placement);
    }
  }
  const inventory: IRuntimeInventoryEntry[] = [];
  for (const component of runtime.getAllComponents()) {
    const mount = component.mount.trim();
    if (mount.length === 0) {
      continue;
    }
    const previousPlacement = previousPlacementByMount.get(mount)
      ?? placementForMount(mount, mount, 'named-instance', true);
    const description = typeof (component.constructor as { description?: unknown }).description === 'string'
      ? (component.constructor as { description?: string }).description
      : undefined;
    inventory.push({
      mount,
      ...(component.constructor.name ? { type: component.constructor.name } : {}),
      runtimeId: registration.runtimeId,
      claimKind: previousPlacement.claimMode,
      placement: previousPlacement,
      ...(description ? { description } : {}),
      ...(hasIntrospectChildren(component) ? { hasChildren: true } : {}),
    });
  }
  appendStandbyPlacementResults(inventory, runtime, registration.runtimeId);
  return inventory;
}

function appendStandbyPlacementResults(
  inventory: IRuntimeInventoryEntry[],
  runtime: MatrixRuntime,
  runtimeId: string,
): void {
  const seen = new Set(inventory.map((entry) => entry.mount));
  for (const standby of readRunnerPlacementStandbyResults(runtime)) {
    if (standby.runtimeId !== runtimeId || seen.has(standby.mount)) {
      continue;
    }
    inventory.push({
      mount: standby.mount,
      runtimeId,
      claimKind: standby.placement.claimMode,
      placement: standby.placement,
    });
    seen.add(standby.mount);
  }
}

function buildRuntimePresenceRecord(params: {
  runtimeId: string;
  runtimeRoot: string;
  manifest: ILoadedMatrixServiceManifest;
  environment: ILoadedMatrixPackageEnvironment | undefined;
  actorCount: number;
  inventory: readonly IRuntimeInventoryEntry[];
  serviceMount: string | undefined;
  runtimeMount: string | undefined;
  controlMount: string | undefined;
  runnerTransport: IResolvedRunnerTransportPlan | undefined;
  webappRoute: IRunnerWebappRouteMetadata | undefined;
  hostPlacement: IRunnerHostPlacement | undefined;
}): RuntimePresenceRecordV1 {
  const now = Date.now();
  const namespaceRoot = params.runtimeRoot;
  return {
    version: '1',
    namespaceRoot,
    runtimeId: params.runtimeId,
    runtimeType: 'folder',
    runtimeRoot: params.runtimeRoot,
    authorityRoot: namespaceRoot,
    app: params.manifest.packageName,
    claims: buildRuntimeClaims(params.serviceMount, params.environment),
    inventoryMode: 'embedded',
    inventory: [...params.inventory],
    ...(params.controlMount ? { controlMount: params.controlMount } : {}),
    heartbeatTtlMs: RUNTIME_PRESENCE_TTL_MS,
    registeredAt: now,
    lastHeartbeat: now,
    health: {
      status: 'ok',
      updatedAt: now,
    },
    metadata: {
      source: 'mx-runner-runtime-presence',
      actorCount: params.actorCount,
      packageDir: params.manifest.packageDir,
      packageName: params.manifest.packageName,
      // Runtime displayName is set by host-service at spawn (--name or
      // generated). The host passes it via env so the runtime can publish
      // it in its registry presence record. Consumers read this field
      // directly; no derivation from package or runtimeId.
      ...(process.env.MATRIX_RUNTIME_DISPLAY_NAME ? { displayName: process.env.MATRIX_RUNTIME_DISPLAY_NAME } : {}),
      ...(params.environment ? {
        environmentName: params.environment.envName,
        environmentPath: params.environment.environmentPath,
      } : {}),
      ...(params.runtimeMount ? { runtimeMount: params.runtimeMount } : {}),
      ...(params.manifest.mount ? { serviceMount: params.manifest.mount } : {}),
      ...(params.environment?.environment.package?.publicRoot ? {
        publicRoot: params.environment.environment.package.publicRoot,
      } : {}),
      ...(params.runnerTransport ? { runnerTransport: params.runnerTransport } : {}),
      ...(params.webappRoute ? { webapp: params.webappRoute } : {}),
      ...hostPlacementMetadata(params.hostPlacement),
    },
  };
}

function hasIntrospectChildren(component: MatrixActor): boolean {
  const constructor = component.constructor as { readonly hasDynamicChildren?: unknown };
  if (constructor.hasDynamicChildren === true) {
    return true;
  }
  try {
    const introspection = component.on$introspect({ depth: 'basic' });
    return Array.isArray(introspection.children) && introspection.children.length > 0;
  } catch {
    return false;
  }
}

async function registerRuntimeInventoryClaims(
  runtime: MatrixRuntime,
  logicalRegistryMount: string,
  manifest: ILoadedMatrixServiceManifest,
  environment: ILoadedMatrixPackageEnvironment | undefined,
  runtimeId: string,
  runtimeWireRoot: string,
  inventory: readonly IRuntimeInventoryEntry[],
  _serviceMount: string | undefined,
  webappRoute: IRunnerWebappRouteMetadata | undefined,
  hostPlacement: IRunnerHostPlacement | undefined,
  registryOptional: boolean,
): Promise<number> {
  if (registryOptional) {
    return 0;
  }
  const authorityRoot = environment?.environment.runtime.root
    ?? manifest.root
    ?? runtimeWireRoot;
  const timeoutMs = controlPlaneRequestTimeoutMs(environment);
  const requestOptions = controlPlaneRequestOptions(runtime, environment, timeoutMs);
  let registered = 0;
  for (const entry of inventory) {
    const logicalMount = entry.mount.trim();
    if (entry.placement.callable === false) {
      continue;
    }
    if (!shouldRegisterRuntimeInventoryClaim(runtimeId, logicalMount)) {
      continue;
    }
    await RequestReply.execute(
      runtime.getRootContext(),
      logicalRegistryMount,
      'registry.claim',
      {
        mount: logicalMount,
        kind: 'actor',
        componentId: `${manifest.packageName}:inventory:${logicalMount}`,
        componentType: entry.type ?? 'actor',
        authorityRoot,
        scope: 'identity-relative',
        providerRuntimeId: runtimeId,
        runtimeWireRoot,
        localMount: logicalMount,
        packageName: manifest.packageName,
        mode: entry.placement.claimMode,
        cardinality: entry.placement.cardinality,
        claimMode: entry.placement.claimMode,
        logicalMount: entry.placement.logicalMount,
        physicalMount: entry.placement.physicalMount,
        callable: entry.placement.callable,
        ...(entry.placement.standbyReason ? { standbyReason: entry.placement.standbyReason } : {}),
        ...(typeof entry.placement.placementEpoch === 'number' ? { placementEpoch: entry.placement.placementEpoch } : {}),
        ...registryClaimPlacement(hostPlacement),
        ttlMs: 30_000,
        metadata: {
          source: 'runner-runtime-inventory',
          placement: entry.placement,
          ...(entry.description ? { description: entry.description } : {}),
          ...(entry.hasChildren === true ? { hasChildren: true } : {}),
          ...hostPlacementMetadata(hostPlacement),
        },
      },
      requestOptions,
    );
    registered++;
  }
  if (webappRoute) {
    registered += await registerWebappSurfaceClaim(
      runtime,
      logicalRegistryMount,
      manifest,
      authorityRoot,
      runtimeId,
      runtimeWireRoot,
      webappRoute,
      hostPlacement,
      requestOptions,
    );
  }
  return registered;
}

async function registerWebappSurfaceClaim(
  runtime: MatrixRuntime,
  logicalRegistryMount: string,
  manifest: ILoadedMatrixServiceManifest,
  authorityRoot: string,
  runtimeId: string,
  runtimeWireRoot: string,
  webappRoute: IRunnerWebappRouteMetadata,
  hostPlacement: IRunnerHostPlacement | undefined,
  requestOptions: IControlPlaneRequestOptions,
): Promise<number> {
  const appName = webappRoute.appName.trim();
  if (!appName) {
    return 0;
  }
  const routePrefix = normalizeWebappRoutePrefix(webappRoute.routePrefix, appName);
  const placement = placementForMount(
    webappRoute.assetMount ?? appName,
    appName,
    'named-instance',
    true,
  );
  const displayName = readOptionalString(webappRoute.displayName);
  const icon = readOptionalString(webappRoute.icon);
  const description = readOptionalString(webappRoute.description);
  const shells = [...new Set((webappRoute.shells ?? []).map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
  await RequestReply.execute(
    runtime.getRootContext(),
    logicalRegistryMount,
    'registry.claim',
    {
      mount: appName,
      kind: 'app',
      componentId: `${manifest.packageName}:webapp:${appName}`,
      componentType: 'webapp',
      authorityRoot,
      scope: 'identity-relative',
      providerRuntimeId: runtimeId,
      runtimeWireRoot,
      localMount: webappRoute.assetMount ?? appName,
      packageName: manifest.packageName,
      runtimeId,
      packageId: manifest.packageName,
      packageRef: manifest.packageName,
      mode: placement.claimMode,
      cardinality: placement.cardinality,
      claimMode: placement.claimMode,
      logicalMount: placement.logicalMount,
      physicalMount: placement.physicalMount,
      callable: placement.callable,
      ...registryClaimPlacement(hostPlacement),
      ttlMs: 30_000,
      app: {
        route: routePrefix,
        title: displayName ?? titleFromAppName(appName),
        ...(icon ? { icon } : {}),
        surface: 'page',
        openable: true,
        appName,
      },
      metadata: {
        source: 'runner-webapp-surface',
        placement,
        routeKind: webappRoute.assetMount ? 'matrix-asset-endpoint' : 'standalone-webapp',
        ...(description ? { description } : {}),
        ...(shells.length > 0 ? { shells } : {}),
        ...(typeof webappRoute.navOrder === 'number' && Number.isFinite(webappRoute.navOrder) ? { navOrder: webappRoute.navOrder } : {}),
        ...(webappRoute.assetMount ? { assetMount: webappRoute.assetMount } : {}),
        ...(webappRoute.origin ? { origin: webappRoute.origin } : {}),
        ...(typeof webappRoute.port === 'number' ? { port: webappRoute.port } : {}),
        ...hostPlacementMetadata(hostPlacement),
      },
    },
    requestOptions,
  );
  return 1;
}

function controlPlaneRequestOptions(
  runtime: MatrixRuntime,
  environment: ILoadedMatrixPackageEnvironment | undefined,
  timeoutMs: number,
): IControlPlaneRequestOptions {
  const targetRoot = environment?.environment.runtime.root
    ?? readTransportRoot(runtime);
  const protocolRequest = isHostManagedEnvironment(environment)
    && typeof environment?.environment.nats?.credentialsRef === 'string'
    && environment.environment.nats.credentialsRef.trim().length > 0;
  return {
    timeoutMs,
    ...(targetRoot ? { targetRoot } : {}),
    ...(protocolRequest ? { protocolRequest: true } : {}),
  };
}

function registrationControlPlaneRequestOptions(
  registration: Pick<IRunnerRuntimeRegistration | IRunnerBindingRegistration, 'controlTargetRoot' | 'protocolRequest'>,
  timeoutMs: number,
): IControlPlaneRequestOptions {
  return {
    timeoutMs,
    ...(registration.controlTargetRoot ? { targetRoot: registration.controlTargetRoot } : {}),
    ...(registration.protocolRequest === true ? { protocolRequest: true } : {}),
  };
}

function shouldPublishBindingForwards(environment: ILoadedMatrixPackageEnvironment | undefined): boolean {
  return !isHostManagedEnvironment(environment);
}

function controlPlaneRequestTimeoutMs(environment: ILoadedMatrixPackageEnvironment | undefined): number {
  return environment?.environment.nats?.credentialsRef
    ? LINKED_CONTROL_PLANE_REQUEST_TIMEOUT_MS
    : LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS;
}

function normalizeWebappRoutePrefix(value: string | undefined, appName: string): string {
  const routePrefix = value?.trim() || `/apps/${appName}/`;
  return routePrefix.endsWith('/') ? routePrefix : `${routePrefix}/`;
}

function readOptionalString(value: string | undefined): string | undefined {
  const trimmed = value?.trim() ?? '';
  return trimmed.length > 0 ? trimmed : undefined;
}

function titleFromAppName(appName: string): string {
  return appName
    .split(/[-_.]/)
    .filter(Boolean)
    .map((segment) => `${segment.charAt(0).toUpperCase()}${segment.slice(1)}`)
    .join(' ');
}

export function shouldRegisterRuntimeInventoryClaim(runtimeId: string, logicalMount: string): boolean {
  const trimmedRuntimeId = runtimeId.trim();
  const trimmedMount = logicalMount.trim();
  if (!trimmedRuntimeId || !trimmedMount) {
    return false;
  }
  const runtimeMount = `system.runtimes.${trimmedRuntimeId}`;
  if (trimmedMount === runtimeMount || trimmedMount.startsWith(`${runtimeMount}.`)) {
    return false;
  }
  return true;
}

function buildRuntimeClaims(
  serviceMount: string | undefined,
  environment: ILoadedMatrixPackageEnvironment | undefined,
): Array<{ prefix: string; kind: 'authoritative' }> {
  const claims = new Set<string>();
  const publicRoot = environment?.environment.package?.publicRoot?.trim();
  if (publicRoot) {
    claims.add(publicRoot);
  }
  const resolvedServiceMount = serviceMount?.trim();
  if (resolvedServiceMount) {
    claims.add(resolvedServiceMount);
  }
  return [...claims].map((prefix) => ({ prefix, kind: 'authoritative' as const }));
}

function deriveCanonicalBindings(
  manifest: ILoadedMatrixServiceManifest,
  environment: ILoadedMatrixPackageEnvironment | undefined,
  serviceMount: string | undefined,
): ICanonicalBindingDefinition[] {
  const bindings = new Map<string, ICanonicalBindingDefinition>();
  const packageName = manifest.packageName;
  const publicRoot = trimToUndefined(environment?.environment.package?.publicRoot)
    ?? trimToUndefined(manifest.packageNamespace);
  const resolvedServiceMount = trimToUndefined(serviceMount)
    ?? trimToUndefined(manifest.mount);
  const rootKind = trimToUndefined(manifest.serviceInstance.rootKind) ?? 'package-root';

  if (rootKind === 'package-root' && manifest.packageRoot) {
    const canonicalRoot = resolveCanonicalRootBinding(manifest.packageRoot, publicRoot);
    const localRootMount = resolvedServiceMount
      ?? resolveLocalRootMount(manifest.packageRoot, publicRoot);
    if (canonicalRoot && localRootMount) {
      bindings.set(canonicalRoot, {
        binding: canonicalRoot,
        localMount: localRootMount,
        ops: manifest.packageRoot.accepts,
        packageName,
      });
    }
  }

  for (const declaration of manifest.packageComponents) {
    const binding = resolveCanonicalComponentBinding(declaration, publicRoot);
    const localMount = resolveLocalComponentMount(declaration, resolvedServiceMount, rootKind);
    if (!binding || !localMount) {
      continue;
    }
    bindings.set(binding, {
      binding,
      localMount,
      ops: declaration.accepts,
      packageName,
    });
  }

  return [...bindings.values()];
}

function resolveCanonicalRootBinding(
  declaration: ILoadedMatrixBindingDeclaration,
  publicRoot: string | undefined,
): string | undefined {
  if (isExplicitAbsoluteMount(declaration.mount)) {
    return declaration.mount;
  }
  return publicRoot ?? declaration.mount;
}

function resolveCanonicalComponentBinding(
  declaration: ILoadedMatrixBindingDeclaration,
  publicRoot: string | undefined,
): string | undefined {
  if (isExplicitAbsoluteMount(declaration.mount)) {
    return declaration.mount;
  }
  if (!publicRoot) {
    return undefined;
  }
  return `${publicRoot}.${declaration.mount}`;
}

function resolveLocalRootMount(
  declaration: ILoadedMatrixBindingDeclaration,
  publicRoot: string | undefined,
): string | undefined {
  return declaration.mount
    || publicRoot;
}

function resolveLocalComponentMount(
  declaration: ILoadedMatrixBindingDeclaration,
  serviceMount: string | undefined,
  rootKind: string,
): string | undefined {
  if (isExplicitAbsoluteMount(declaration.mount)) {
    return declaration.mount;
  }
  if (rootKind === 'package-root' && serviceMount) {
    return `${serviceMount}.${declaration.mount}`;
  }
  return declaration.mount;
}

function isExplicitAbsoluteMount(mount: string): boolean {
  return mount.includes('.');
}

function trimToUndefined(value: unknown): string | undefined {
  if (typeof value !== 'string') {
    return undefined;
  }
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : undefined;
}

function readPlacementDeclarations(manifest: ILoadedMatrixServiceManifest): IPlacementDeclarationIndex {
  const byMount = new Map<string, MatrixMountCardinality>();
  const manifestRecord = readJsonObjectIfPresent(path.join(manifest.packageDir, 'matrix.json'));
  if (!manifestRecord) {
    return { byMount };
  }
  addPlacementDeclaration(byMount, manifestRecord.root);
  const components = manifestRecord.components;
  if (Array.isArray(components)) {
    for (const component of components) {
      addPlacementDeclaration(byMount, component);
    }
  }
  return { byMount };
}

function addPlacementDeclaration(
  byMount: Map<string, MatrixMountCardinality>,
  value: unknown,
): void {
  if (!isRecord(value)) {
    return;
  }
  const mount = trimToUndefined(value.mount);
  if (!mount) {
    return;
  }
  const placement = isRecord(value.placement) ? value.placement : undefined;
  const cardinality = readMountCardinality(placement?.cardinality);
  if (cardinality) {
    byMount.set(mount, cardinality);
  }
}

function resolveCardinalityForMount(
  declarations: IPlacementDeclarationIndex,
  mount: string,
): MatrixMountCardinality {
  return declarations.byMount.get(mount) ?? 'named-instance';
}

function placementForMount(
  physicalMount: string,
  logicalMount: string,
  cardinality: MatrixMountCardinality,
  callable: boolean,
): RuntimeInventoryPlacementMetadata {
  return {
    cardinality,
    claimMode: claimModeForCardinality(cardinality),
    logicalMount,
    physicalMount,
    callable,
  };
}

function claimModeForCardinality(cardinality: MatrixMountCardinality): MatrixPlacementClaimMode {
  if (cardinality === 'authority-singleton') {
    return 'authoritative';
  }
  if (cardinality === 'queue-service') {
    return 'pool-member';
  }
  if (cardinality === 'replicated-read') {
    return 'mirror';
  }
  return 'local-only';
}

function readMountCardinality(value: unknown): MatrixMountCardinality | undefined {
  return value === 'authority-singleton'
    || value === 'device-singleton'
    || value === 'device-local-control'
    || value === 'queue-service'
    || value === 'named-instance'
    || value === 'replicated-read'
    ? value
    : undefined;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}

function readRecord(value: unknown): Record<string, unknown> | undefined {
  return isRecord(value) ? value : undefined;
}

function resolveRunnerHostPlacement(
  runtime: MatrixRuntime,
  environment: ILoadedMatrixPackageEnvironment | undefined,
): IRunnerHostPlacement | undefined {
  const hostHome = trimToUndefined(runtime.getRootContext().getService<unknown>('matrix-host-home'))
    ?? trimToUndefined(environment?.environment.host?.matrixDir);
  if (!hostHome) {
    return undefined;
  }

  const credentialsDir = path.join(hostHome, 'credentials');
  const linkRecord = readJsonObjectIfPresent(path.join(credentialsDir, 'hivecast-link.json'));
  const installRecord = readJsonObjectIfPresent(path.join(credentialsDir, 'hivecast-install.json'));
  const hostId = trimToUndefined(linkRecord?.hostId) ?? trimToUndefined(installRecord?.installId);
  if (!hostId) {
    return undefined;
  }
  const hostName = trimToUndefined(linkRecord?.hostName) ?? trimToUndefined(installRecord?.hostName);
  const deviceSlug = trimToUndefined(linkRecord?.deviceSlug);
  return {
    deviceId: hostId,
    hostId,
    ...(hostName ? { hostName } : {}),
    ...(deviceSlug ? { deviceSlug } : {}),
  };
}

function registryClaimPlacement(hostPlacement: IRunnerHostPlacement | undefined): Record<string, string> {
  return hostPlacement
    ? {
        deviceId: hostPlacement.deviceId,
        hostId: hostPlacement.hostId,
      }
    : {};
}

function hostPlacementMetadata(hostPlacement: IRunnerHostPlacement | undefined): Record<string, string> {
  return hostPlacement
    ? {
        deviceId: hostPlacement.deviceId,
        hostId: hostPlacement.hostId,
        ...(hostPlacement.hostName ? { hostName: hostPlacement.hostName } : {}),
        ...(hostPlacement.deviceSlug ? { deviceSlug: hostPlacement.deviceSlug } : {}),
      }
    : {};
}

function readJsonObjectIfPresent(filePath: string): Record<string, unknown> | undefined {
  if (!fs.existsSync(filePath)) {
    return undefined;
  }
  const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '')) as unknown;
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
    throw new Error(`Expected JSON object at ${filePath}`);
  }
  return parsed as Record<string, unknown>;
}

async function ensureRegistryActor<TActor extends object>(
  runtime: MatrixRuntime,
  mount: string,
  ActorClass: new () => TActor,
): Promise<boolean> {
  if (runtime.hasComponent(mount)) {
    return false;
  }
  await runtime.createSupervised(ActorClass as never, mount);
  return true;
}
