import type { MatrixActor } from '../core/MatrixActor';
import type { IMatrixContext } from '../engine/core/IMatrixContext';
import type { ITransportMessageMeta } from '../engine/remoting/ITransportMessageMeta';
import type {
  HealthSnapshotV1,
  HealthStatusV1,
} from '@open-matrix/contracts/service-registry';
import type {
  RuntimeClaimKind,
  RuntimeInventoryEntryV1,
  RuntimeInventoryMode,
  RuntimePresenceEventV1,
  RuntimePresenceRecordV1,
  RuntimeType,
} from '@open-matrix/contracts/runtime-presence';
import type { RuntimeInventoryPlacementMetadata } from '@open-matrix/contracts/placement';

export type RuntimePresenceSource = MatrixActor | IMatrixContext;

export type RuntimePresenceHandler = (
  record: RuntimePresenceRecordV1,
  event: RuntimePresenceEventV1,
  meta: ITransportMessageMeta,
) => void | Promise<void>;

const RUNTIME_PRESENCE_EVENTS: readonly RuntimePresenceEventV1[] = [
  'announce',
  'heartbeat',
  'departed',
];

export function runtimePresenceTopic(event: RuntimePresenceEventV1): string {
  return `$runtime.${event}`;
}

export function publishRuntimePresence(
  source: RuntimePresenceSource,
  payload: RuntimePresenceRecordV1,
  event: RuntimePresenceEventV1 = 'heartbeat',
): void {
  const context = contextFromPresenceSource(source);
  if (!context) {
    throw new Error('publishRuntimePresence requires an initialized Matrix actor or context');
  }
  const namespaceRoot = payload.namespaceRoot.trim() || context.transport.root.trim();
  if (!namespaceRoot) {
    throw new Error('publishRuntimePresence requires a namespaceRoot or transport root');
  }
  context.transport.publish(runtimePresenceTopic(event), {
    ...payload,
    namespaceRoot,
  });
}

export function subscribeRuntimePresence(
  source: RuntimePresenceSource,
  namespaceRoot: string,
  handler: RuntimePresenceHandler,
): () => void {
  const context = contextFromPresenceSource(source);
  if (!context) {
    throw new Error('subscribeRuntimePresence requires an initialized Matrix actor or context');
  }
  const expectedNamespaceRoot = namespaceRoot.trim() || context.transport.root.trim();
  if (!expectedNamespaceRoot) {
    throw new Error('subscribeRuntimePresence requires a namespaceRoot or transport root');
  }

  const unsubs = RUNTIME_PRESENCE_EVENTS.map((event) => (
    context.transport.subscribe(runtimePresenceTopic(event), (payload, meta) => {
      const record = readRuntimePresenceRecord(payload);
      if (!record || record.namespaceRoot !== expectedNamespaceRoot) {
        return;
      }
      return handler(record, event, meta);
    })
  ));

  return () => {
    for (const unsub of unsubs) {
      unsub();
    }
  };
}

function contextFromPresenceSource(source: RuntimePresenceSource): IMatrixContext | undefined {
  if (isMatrixContext(source)) {
    return source;
  }
  return source.context;
}

function isMatrixContext(source: RuntimePresenceSource): source is IMatrixContext {
  const candidate = source as IMatrixContext;
  return (
    typeof candidate.mount === 'string' &&
    typeof candidate.transport?.publish === 'function' &&
    typeof candidate.transport.subscribe === 'function'
  );
}

function readRuntimePresenceRecord(value: unknown): RuntimePresenceRecordV1 | null {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return null;
  }
  const record = value as Record<string, unknown>;
  const version = record.version;
  const namespaceRoot = readString(record.namespaceRoot);
  const runtimeId = readString(record.runtimeId);
  const runtimeType = readRuntimeType(record.runtimeType);
  const runtimeRoot = readString(record.runtimeRoot);
  const inventoryMode = readInventoryMode(record.inventoryMode);
  const heartbeatTtlMs = readNonNegativeInteger(record.heartbeatTtlMs);
  const registeredAt = readNonNegativeInteger(record.registeredAt);
  const lastHeartbeat = readNonNegativeInteger(record.lastHeartbeat);

  if (
    version !== '1' ||
    !namespaceRoot ||
    !runtimeId ||
    !runtimeType ||
    !runtimeRoot ||
    !inventoryMode ||
    heartbeatTtlMs === undefined ||
    registeredAt === undefined ||
    lastHeartbeat === undefined
  ) {
    return null;
  }

  const inventory = readRuntimeInventory(record.inventory);
  const metadata = readMetadata(record.metadata);
  const health = readHealthSnapshot(record.health);

  return {
    version: '1',
    namespaceRoot,
    runtimeId,
    runtimeType,
    runtimeRoot,
    ...(readString(record.authorityRoot) ? { authorityRoot: readString(record.authorityRoot) } : {}),
    ...(readString(record.platformRoot) ? { platformRoot: readString(record.platformRoot) } : {}),
    ...(readString(record.app) ? { app: readString(record.app) } : {}),
    claims: readRuntimeClaims(record.claims),
    inventoryMode,
    ...(inventory.length > 0 ? { inventory } : {}),
    ...(readString(record.catalogMount) ? { catalogMount: readString(record.catalogMount) } : {}),
    ...(readString(record.controlMount) ? { controlMount: readString(record.controlMount) } : {}),
    heartbeatTtlMs,
    registeredAt,
    lastHeartbeat,
    ...(health ? { health } : {}),
    ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
  };
}

function readRuntimeClaims(value: unknown): RuntimePresenceRecordV1['claims'] {
  if (!Array.isArray(value)) {
    return [];
  }
  return value.flatMap((item) => {
    if (!item || typeof item !== 'object' || Array.isArray(item)) {
      return [];
    }
    const record = item as Record<string, unknown>;
    const prefix = readString(record.prefix);
    const kind = readClaimKind(record.kind);
    return prefix && kind ? [{ prefix, kind }] : [];
  });
}

function readRuntimeInventory(value: unknown): RuntimeInventoryEntryV1[] {
  if (!Array.isArray(value)) {
    return [];
  }
  return value.flatMap((item) => {
    if (!item || typeof item !== 'object' || Array.isArray(item)) {
      return [];
    }
    const record = item as Record<string, unknown>;
    const mount = readString(record.mount);
    const runtimeId = readString(record.runtimeId);
    const claimKind = readClaimKind(record.claimKind);
    if (!mount || !runtimeId || !claimKind) {
      return [];
    }
    const placement = readPlacement(record.placement);
    return [{
      mount,
      ...(readString(record.type) ? { type: readString(record.type) } : {}),
      ...(readSurface(record.surface) ? { surface: readSurface(record.surface) } : {}),
      runtimeId,
      claimKind,
      ...(placement ? { placement } : {}),
      ...(readString(record.description) ? { description: readString(record.description) } : {}),
    }];
  });
}

function readPlacement(value: unknown): RuntimeInventoryEntryV1['placement'] | undefined {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return undefined;
  }
  const record = value as Record<string, unknown>;
  const cardinality = readMountCardinality(record.cardinality);
  const claimMode = readPlacementClaimMode(record.claimMode);
  const logicalMount = readString(record.logicalMount);
  const physicalMount = readString(record.physicalMount);
  if (!cardinality || !claimMode || !logicalMount || !physicalMount || typeof record.callable !== 'boolean') {
    return undefined;
  }
  const standbyReason = readString(record.standbyReason);
  const placementEpoch = readNonNegativeInteger(record.placementEpoch);
  return {
    cardinality,
    claimMode,
    logicalMount,
    physicalMount,
    callable: record.callable,
    ...(standbyReason ? { standbyReason } : {}),
    ...(placementEpoch !== undefined ? { placementEpoch } : {}),
  };
}

function readString(value: unknown): string {
  return typeof value === 'string' ? value.trim() : '';
}

function readNonNegativeInteger(value: unknown): number | undefined {
  if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
    return undefined;
  }
  return Math.floor(value);
}

function readClaimKind(value: unknown): RuntimeClaimKind | undefined {
  const kind = readString(value);
  if (kind === 'authoritative' || kind === 'proxy' || kind === 'mirror' || kind === 'local-only' || kind === 'pool-member') {
    return kind;
  }
  return undefined;
}

function readMountCardinality(value: unknown): RuntimeInventoryPlacementMetadata['cardinality'] | undefined {
  const cardinality = readString(value);
  if (
    cardinality === 'authority-singleton' ||
    cardinality === 'device-singleton' ||
    cardinality === 'device-local-control' ||
    cardinality === 'queue-service' ||
    cardinality === 'named-instance' ||
    cardinality === 'replicated-read'
  ) {
    return cardinality;
  }
  return undefined;
}

function readPlacementClaimMode(value: unknown): RuntimeInventoryPlacementMetadata['claimMode'] | undefined {
  const claimMode = readString(value);
  if (
    claimMode === 'authoritative' ||
    claimMode === 'local-only' ||
    claimMode === 'pool-member' ||
    claimMode === 'mirror'
  ) {
    return claimMode;
  }
  return undefined;
}

function readRuntimeType(value: unknown): RuntimeType | undefined {
  const type = readString(value);
  if (
    type === 'daemon' ||
    type === 'browser' ||
    type === 'cell' ||
    type === 'container' ||
    type === 'leaf' ||
    type === 'worker' ||
    type === 'folder'
  ) {
    return type;
  }
  return undefined;
}

function readInventoryMode(value: unknown): RuntimeInventoryMode | undefined {
  const mode = readString(value);
  if (mode === 'embedded' || mode === 'pull') {
    return mode;
  }
  return undefined;
}

function readSurface(value: unknown): RuntimeInventoryEntryV1['surface'] | undefined {
  const surface = readString(value);
  if (surface === 'headless' || surface === 'dom' || surface === 'webapp') {
    return surface;
  }
  return undefined;
}

function readHealthSnapshot(value: unknown): HealthSnapshotV1 | undefined {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return undefined;
  }
  const record = value as Record<string, unknown>;
  const status = readHealthStatus(record.status);
  const updatedAt = readNonNegativeInteger(record.updatedAt);
  if (!status || updatedAt === undefined) {
    return undefined;
  }
  const reason = readString(record.reason);
  return {
    status,
    ...(reason ? { reason } : {}),
    updatedAt,
  };
}

function readHealthStatus(value: unknown): HealthStatusV1 | undefined {
  const status = readString(value);
  if (
    status === 'ok' ||
    status === 'degraded' ||
    status === 'error' ||
    status === 'unknown' ||
    status === 'starting' ||
    status === 'stopped'
  ) {
    return status;
  }
  return undefined;
}

function readMetadata(value: unknown): Record<string, unknown> {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return {};
  }
  return { ...(value as Record<string, unknown>) };
}
