import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { randomBytes } from 'node:crypto';

type JsonRecord = Record<string, unknown>;

export interface IHiveCastNatsConfig {
  readonly url: string;
  readonly wsUrl?: string;
  readonly leafnodeUrl?: string;
}

export interface IHiveCastNatsCredentials {
  readonly accountSeed?: string;
  readonly jwt?: string;
  readonly seed?: string;
}

export interface IHiveCastHostLinkRecord {
  readonly version: 1;
  readonly cloudUrl: string;
  readonly deviceRegistryRoot?: string;
  readonly hostLinkId?: string;
  readonly hostId?: string;
  readonly principalId?: string;
  readonly hostName?: string;
  readonly deviceSlug?: string;
  readonly authorityCoordinator?: boolean;
  readonly spaceId?: string;
  readonly routeKey?: string;
  readonly publicNamespace?: string;
  readonly authorityRoot: string;
  readonly linkedAt: string;
  readonly credentials: {
    readonly hostLinkTokenRef?: string;
    readonly registryTokenRef?: string;
    readonly natsCredentialRef: string;
    readonly natsLeafnodeCredentialRef?: string;
  };
}

interface ILocalOwnerTransportSnapshot {
  readonly root: string;
  readonly authorityRoot?: string;
  readonly nats: JsonRecord;
}

export interface IHiveCastLocalOwnerTransport {
  readonly root: string;
  readonly authorityRoot?: string;
}

interface ILinkedAuthorityTransportSnapshot {
  readonly authorityRoot: string;
  readonly nats: JsonRecord;
  readonly leafnode?: {
    readonly url: string;
    readonly credentialsRef: string;
  };
  readonly authorityCoordinator?: boolean;
  readonly routeKey?: string;
  readonly publicNamespace?: string;
  readonly spaceId?: string;
}

export interface IHiveCastLinkPaths {
  readonly matrixHome: string;
  readonly credentialsDir: string;
  readonly installIdentityPath: string;
  readonly linkPath: string;
  readonly natsCredentialsPath: string;
  readonly natsLeafnodeCredentialsPath: string;
  readonly hostLinkTokenPath: string;
  readonly hostCredentialsPath: string;
  readonly hostConfigPath: string;
}

export interface IHiveCastInstallIdentity {
  readonly version: 1;
  readonly installId: string;
  readonly hostName?: string;
  readonly createdAt: string;
  readonly updatedAt: string;
}

export interface ISaveHiveCastHostLinkOptions {
  readonly cwd: string;
  readonly matrixHome?: string;
  readonly cloudUrl: string;
  readonly deviceRegistryRoot?: string;
  readonly authorityRoot: string;
  readonly nats: IHiveCastNatsConfig;
  readonly natsCredentials: IHiveCastNatsCredentials;
  readonly hostLinkToken?: string;
  readonly hostLinkId?: string;
  readonly hostId?: string;
  readonly principalId?: string;
  readonly hostName?: string;
  readonly deviceSlug?: string;
  readonly authorityCoordinator?: boolean;
  readonly spaceId?: string;
  readonly routeKey?: string;
  readonly publicNamespace?: string;
  readonly linkedAt?: string;
}

export interface IHiveCastLinkStatus {
  readonly linked: boolean;
  readonly matrixHome: string;
  readonly linkPath: string;
  readonly natsCredentialsPath: string;
  readonly hostConfigPath: string;
  readonly natsCredentialsPresent: boolean;
  readonly hostConfigPresent: boolean;
  readonly hostConfigLinked: boolean;
  readonly hostLinkId?: string;
  readonly authorityRoot?: string;
  readonly routeKey?: string;
  readonly publicNamespace?: string;
  readonly spaceId?: string;
  readonly authorityCoordinator?: boolean;
  readonly cloudUrl?: string;
  readonly linkedAt?: string;
}

export interface IRemoveHiveCastHostLinkResult {
  readonly removed: boolean;
  readonly hostConfigReset: boolean;
  readonly paths: IHiveCastLinkPaths;
}

export interface IRemoveHiveCastHostLinkOptions {
  readonly preserveCredentials?: boolean;
}

const DEFAULT_MATRIX_HOME = path.join(os.homedir(), '.matrix');
const HIVECAST_NATS_JSON_CREDENTIAL_REF = 'file:credentials/hivecast-nats.json';
const HIVECAST_NATS_LEAFNODE_CREDENTIAL_REF = 'file:credentials/hivecast-nats.creds';
const HIVECAST_DEFAULT_RUNTIME_KEYS = [
  'SYSTEM',
  'GATEWAY',
  'INFERENCE',
  'AGENTS',
  'WEB',
  'EDGE',
  'DIRECTOR',
  'CHAT',
  'INFERENCE-SETTINGS',
  'FLOWPAD',
  'SMITHERS',
  'HOST-CONTROL',
  'HOST-OPS',
] as const;

function asRecord(value: unknown): JsonRecord | null {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return null;
  }
  return value as JsonRecord;
}

function optionalString(value: unknown): string | undefined {
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
}

function expandHome(value: string): string {
  if (value === '~') {
    return os.homedir();
  }
  return value.startsWith('~/') ? path.join(os.homedir(), value.slice(2)) : value;
}

export function resolveHiveCastMatrixHome(cwd: string, matrixHome?: string): string {
  const raw = matrixHome
    ?? process.env.MATRIX_HOST_HOME
    ?? process.env.MATRIX_HOME
    ?? DEFAULT_MATRIX_HOME;
  const expanded = expandHome(raw);
  return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(cwd, expanded);
}

export function hiveCastLinkPaths(cwd: string, matrixHome?: string): IHiveCastLinkPaths {
  const resolvedHome = resolveHiveCastMatrixHome(cwd, matrixHome);
  const credentialsDir = path.join(resolvedHome, 'credentials');
  return {
    matrixHome: resolvedHome,
    credentialsDir,
    installIdentityPath: path.join(credentialsDir, 'hivecast-install.json'),
    linkPath: path.join(credentialsDir, 'hivecast-link.json'),
    natsCredentialsPath: path.join(credentialsDir, 'hivecast-nats.json'),
    natsLeafnodeCredentialsPath: path.join(credentialsDir, 'hivecast-nats.creds'),
    hostLinkTokenPath: path.join(credentialsDir, 'hivecast-host-link-token'),
    hostCredentialsPath: path.join(resolvedHome, 'credentials.json'),
    hostConfigPath: path.join(resolvedHome, 'host.json'),
  };
}

export function ensureHiveCastInstallIdentity(options: {
  readonly cwd: string;
  readonly matrixHome?: string;
  readonly hostName?: string;
}): { readonly identity: IHiveCastInstallIdentity; readonly paths: IHiveCastLinkPaths } {
  const paths = hiveCastLinkPaths(options.cwd, options.matrixHome);
  const existing = readJsonFile(paths.installIdentityPath);
  const existingInstallId = optionalString(existing?.installId);
  const now = new Date().toISOString();
  const hostName = optionalString(options.hostName);
  if (existingInstallId) {
    const existingHostName = optionalString(existing?.hostName);
    const nextHostName = hostName ?? existingHostName;
    const identity: IHiveCastInstallIdentity = {
      version: 1,
      installId: existingInstallId,
      ...(nextHostName ? { hostName: nextHostName } : {}),
      createdAt: optionalString(existing?.createdAt) ?? now,
      updatedAt: hostName && hostName !== existingHostName ? now : (optionalString(existing?.updatedAt) ?? now),
    };
    if (hostName && hostName !== existingHostName) {
      writePrivateJson(paths.installIdentityPath, identity);
    }
    return { identity, paths };
  }
  const identity: IHiveCastInstallIdentity = {
    version: 1,
    installId: `install_${randomBytes(10).toString('hex')}`,
    ...(hostName ? { hostName } : {}),
    createdAt: now,
    updatedAt: now,
  };
  writePrivateJson(paths.installIdentityPath, identity);
  return { identity, paths };
}

function localOwnerRootToken(installId: string): string {
  const token = installId
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
  if (!token) {
    throw new Error('HIVECAST_INSTALL_IDENTITY_INVALID: installId cannot produce a local owner root');
  }
  return token;
}

function localOwnerAuthorityRoot(matrixHome: string): string {
  const { identity } = ensureHiveCastInstallIdentity({ cwd: process.cwd(), matrixHome });
  return `local-${localOwnerRootToken(identity.installId)}`;
}

function runtimeScopeToken(installId: string): string {
  const token = installId
    .toUpperCase()
    .replace(/[^A-Z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
  if (!token) {
    throw new Error('HIVECAST_INSTALL_IDENTITY_INVALID: installId cannot produce a runtime scope');
  }
  return token;
}

function installRuntimeScope(matrixHome: string): string {
  const { identity } = ensureHiveCastInstallIdentity({ cwd: process.cwd(), matrixHome });
  return runtimeScopeToken(identity.installId);
}

function writePrivateJson(filePath: string, payload: object): void {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
  try {
    fs.chmodSync(filePath, 0o600);
  } catch {
  }
}

function writePrivateText(filePath: string, payload: string): void {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, payload, 'utf8');
  try {
    fs.chmodSync(filePath, 0o600);
  } catch {
  }
}

function natsUserCredentialsFile(credentials: IHiveCastNatsCredentials): string | undefined {
  const jwt = optionalString(credentials.jwt);
  const seed = optionalString(credentials.seed);
  if (!jwt || !seed) {
    return undefined;
  }
  return [
    '-----BEGIN NATS USER JWT-----',
    jwt,
    '------END NATS USER JWT------',
    '',
    '-----BEGIN USER NKEY SEED-----',
    seed,
    '------END USER NKEY SEED------',
    '',
  ].join('\n');
}

function ownerForPath(filePath: string): { readonly uid: number; readonly gid: number } {
  const stat = fs.statSync(filePath);
  return { uid: stat.uid, gid: stat.gid };
}

function alignOwnership(filePath: string, owner: { readonly uid: number; readonly gid: number }): void {
  if (typeof process.getuid !== 'function' || process.getuid() !== 0) {
    return;
  }
  fs.chownSync(filePath, owner.uid, owner.gid);
}

function readJsonFile(filePath: string): JsonRecord | null {
  if (!fs.existsSync(filePath)) {
    return null;
  }
  try {
    const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as unknown;
    return asRecord(parsed);
  } catch {
    return null;
  }
}

function buildHostConfig(
  existing: JsonRecord | null,
  matrixHome: string,
  localOwnerTransportOverride?: ILocalOwnerTransportSnapshot,
  linkedAuthorityTransport?: ILinkedAuthorityTransportSnapshot,
): JsonRecord {
  const currentHttp = asRecord(existing?.http);
  const currentRuntimeStorage = asRecord(existing?.runtimeStorage);
  const currentPackageStorage = asRecord(existing?.packageStorage);
  const currentAuth = asRecord(existing?.auth);
  const localOwnerTransport = readLocalOwnerTransportSnapshotForHome(matrixHome, existing)
    ?? localOwnerTransportOverride
    ?? captureLocalOwnerTransport(matrixHome, existing);
  const generatedLocalOwnerRoot = localOwnerAuthorityRoot(matrixHome);
  const generatedLocalOwnerTransport = {
    root: generatedLocalOwnerRoot,
    authorityRoot: generatedLocalOwnerRoot,
    addressRoot: generatedLocalOwnerRoot,
    nats: defaultLocalOwnerNatsTransport(),
  };
  const localOwnerHostTransport = localOwnerTransport
    ? localOwnerHostConfigTransport(localOwnerTransport)
    : generatedLocalOwnerTransport;
  const hostTransport = linkedAuthorityTransport
    ? linkedAuthorityTransport.authorityCoordinator === false
      ? linkedLeafHostConfigTransport(linkedAuthorityTransport, localOwnerHostTransport)
      : linkedAuthorityHostConfigTransport(linkedAuthorityTransport)
    : localOwnerHostTransport;

  const nextConfig: JsonRecord = {
    ...(existing ?? {}),
    kind: optionalString(existing?.kind) ?? 'MatrixHostConfig',
    version: typeof existing?.version === 'number' ? existing.version : 1,
    home: matrixHome,
    ...(localOwnerTransport ? { hivecastLocalOwnerTransport: localOwnerTransport } : {}),
    http: currentHttp ?? {
      host: '127.0.0.1',
      port: 3100,
    },
    transport: hostTransport,
    auth: currentAuth ?? {
      mode: 'local-client',
    },
    runtimeStorage: currentRuntimeStorage ?? {
      recordsDir: 'runtimes',
      logsDir: 'logs/runtimes',
    },
    packageStorage: currentPackageStorage ?? {
      globalDir: 'packages/global',
      systemDir: 'packages/system',
    },
  };
  if (linkedAuthorityTransport?.authorityCoordinator === false && linkedAuthorityTransport.leafnode) {
    nextConfig.natsTopology = linkedLeafNatsTopology(hostTransport.nats as JsonRecord, linkedAuthorityTransport.leafnode);
  } else {
    delete nextConfig.natsTopology;
  }
  return nextConfig;
}

function linkedLeafNatsTopology(
  localNats: JsonRecord,
  leafnode: { readonly url: string; readonly credentialsRef: string },
): JsonRecord {
  const clientUrl = optionalString(localNats.url);
  const wsUrl = optionalString(localNats.wsUrl);
  return {
    mode: 'leafnode',
    ...(clientUrl ? { clientUrl } : {}),
    ...(wsUrl ? { wsUrl } : {}),
    leafnodes: [{
      url: leafnode.url,
      credentialsRef: leafnode.credentialsRef,
    }],
  };
}

function assertLinkedHostConfigConverged(
  record: IHiveCastHostLinkRecord,
  hostConfig: JsonRecord,
): void {
  const transport = asRecord(hostConfig.transport);
  const root = optionalString(transport?.root);
  const authorityRoot = optionalString(transport?.authorityRoot);
  const addressRoot = optionalString(transport?.addressRoot);
  for (const [field, actual] of [
    ['transport.root', root],
    ['transport.authorityRoot', authorityRoot],
    ['transport.addressRoot', addressRoot],
  ] as const) {
    if (actual !== record.authorityRoot) {
      throw new Error(
        `HIVECAST_LINK_ROOT_CONVERGENCE_FAILED: expected host config ${field} ${record.authorityRoot}, got ${actual ?? '(missing)'}`,
      );
    }
  }
}

function linkedAuthorityHostConfigTransport(snapshot: ILinkedAuthorityTransportSnapshot): JsonRecord {
  return {
    root: snapshot.authorityRoot,
    authorityRoot: snapshot.authorityRoot,
    addressRoot: snapshot.authorityRoot,
    ...(snapshot.spaceId ? { spaceId: snapshot.spaceId } : {}),
    ...(snapshot.routeKey ? { routeKey: snapshot.routeKey } : {}),
    ...(snapshot.publicNamespace ? { publicNamespace: snapshot.publicNamespace } : {}),
    nats: { ...snapshot.nats },
  };
}

function linkedLeafHostConfigTransport(
  snapshot: ILinkedAuthorityTransportSnapshot,
  localOwnerTransport: JsonRecord,
): JsonRecord {
  return {
    root: snapshot.authorityRoot,
    authorityRoot: snapshot.authorityRoot,
    addressRoot: snapshot.authorityRoot,
    ...(snapshot.spaceId ? { spaceId: snapshot.spaceId } : {}),
    ...(snapshot.routeKey ? { routeKey: snapshot.routeKey } : {}),
    ...(snapshot.publicNamespace ? { publicNamespace: snapshot.publicNamespace } : {}),
    nats: localNatsTransportForLinkedLeaf(snapshot, localOwnerTransport),
  };
}

function localNatsTransportForLinkedLeaf(
  snapshot: ILinkedAuthorityTransportSnapshot,
  localOwnerTransport: JsonRecord,
): JsonRecord {
  const localNats = asRecord(localOwnerTransport.nats);
  return stripNatsCredentialFields(localNats ?? snapshot.nats);
}

function defaultLocalOwnerNatsTransport(): JsonRecord {
  return {
    mode: 'external',
    url: 'nats://127.0.0.1:4222',
    wsUrl: 'ws://127.0.0.1:4223',
    port: 4222,
    wsPort: 4223,
    dataDir: 'nats/host-default',
    pidFile: 'nats/host-default/nats-server.pid',
  };
}

function stripNatsCredentialFields(nats: JsonRecord): JsonRecord {
  const {
    credentialsRef: _credentialsRef,
    credentials: _credentials,
    natsCredentialRef: _natsCredentialRef,
    ...rest
  } = nats;
  return rest;
}

function linkedAuthorityNatsTransport(
  nats: IHiveCastNatsConfig,
  natsCredentialsPath: string,
): JsonRecord {
  const url = optionalString(nats.url);
  if (!url) {
    throw new Error('HIVECAST_LINK_AUTHORITY_NATS_MISSING: linked Device setup requires nats.url from the setup exchange');
  }
  if (/^wss?:\/\//i.test(url)) {
    throw new Error(
      `HIVECAST_LINK_AUTHORITY_NATS_WS_ONLY: linked Device setup requires a server NATS URL for runtimes, got ${url}`,
    );
  }
  const wsUrl = optionalString(nats.wsUrl);
  return {
    mode: 'external',
    url,
    ...(wsUrl ? { wsUrl } : {}),
    credentialsRef: `file:${natsCredentialsPath}`,
  };
}

function localOwnerHostConfigTransport(snapshot: ILocalOwnerTransportSnapshot): JsonRecord {
  return {
    root: snapshot.root,
    authorityRoot: snapshot.authorityRoot ?? snapshot.root,
    addressRoot: snapshot.root,
    nats: { ...snapshot.nats },
  };
}

function captureLocalOwnerTransport(matrixHome: string, existing: JsonRecord | null): ILocalOwnerTransportSnapshot | undefined {
  return readLocalOwnerTransportSnapshotFromTransportForHome(matrixHome, asRecord(existing?.transport));
}

function captureLocalOwnerTransportFromCurrentNats(matrixHome: string, existing: JsonRecord | null): ILocalOwnerTransportSnapshot | undefined {
  const transport = asRecord(existing?.transport);
  const nats = asRecord(transport?.nats);
  if (!nats) return undefined;
  return readLocalOwnerTransportSnapshotFromTransportForHome(matrixHome, {
    root: localOwnerAuthorityRoot(matrixHome),
    nats: { ...nats },
  });
}

function readLocalOwnerTransportSnapshot(config: JsonRecord | null): ILocalOwnerTransportSnapshot | undefined {
  const snapshot = asRecord(config?.hivecastLocalOwnerTransport);
  if (!snapshot) return undefined;
  const root = optionalString(snapshot.root);
  const nats = asRecord(snapshot.nats);
  if (!root || !nats) return undefined;
  return readLocalOwnerTransportSnapshotFromTransport({
    root,
    ...(optionalString(snapshot.authorityRoot) ? { authorityRoot: optionalString(snapshot.authorityRoot) } : {}),
    nats: { ...nats },
  });
}

function readLocalOwnerTransportSnapshotForHome(
  matrixHome: string,
  config: JsonRecord | null,
): ILocalOwnerTransportSnapshot | undefined {
  const snapshot = readLocalOwnerTransportSnapshot(config);
  if (snapshot) return snapshot;
  const saved = asRecord(config?.hivecastLocalOwnerTransport);
  if (!saved) return undefined;
  return readLocalOwnerTransportSnapshotFromTransportForHome(matrixHome, saved);
}

function readLocalOwnerTransportSnapshotFromStatus(matrixHome: string): ILocalOwnerTransportSnapshot | undefined {
  const status = readJsonFile(path.join(matrixHome, 'host.status.json'));
  if (optionalString(status?.status) !== 'running') return undefined;
  return readLocalOwnerTransportSnapshotFromTransportForHome(matrixHome, asRecord(status?.transport));
}

function readLocalOwnerTransportSnapshotFromRuntimeRecords(matrixHome: string): ILocalOwnerTransportSnapshot | undefined {
  const runtimesDir = path.join(matrixHome, 'runtimes');
  if (!fs.existsSync(runtimesDir)) return undefined;
  const localScope = localDefaultRuntimeScope(matrixHome);
  const preferredRuntimeIds = HIVECAST_DEFAULT_RUNTIME_KEYS.map((key) => `RUNTIME-HOST-${localScope}-${key}`);
  for (const runtimeId of preferredRuntimeIds) {
    const snapshot = readLocalOwnerTransportSnapshotFromRuntimeRecord(matrixHome, path.join(runtimesDir, runtimeId, 'runtime.json'));
    if (snapshot) return snapshot;
  }
  for (const entry of fs.readdirSync(runtimesDir, { withFileTypes: true })) {
    if (!entry.isDirectory() || !entry.name.startsWith(`RUNTIME-HOST-${localScope}-`)) continue;
    const snapshot = readLocalOwnerTransportSnapshotFromRuntimeRecord(matrixHome, path.join(runtimesDir, entry.name, 'runtime.json'));
    if (snapshot) return snapshot;
  }
  return undefined;
}

function readLocalOwnerTransportSnapshotFromRuntimeRecord(
  matrixHome: string,
  recordPath: string,
): ILocalOwnerTransportSnapshot | undefined {
  const record = readJsonFile(recordPath);
  const metadata = asRecord(record?.metadata);
  return readLocalOwnerTransportSnapshotFromTransportForHome(matrixHome, asRecord(metadata?.transport));
}

function readLocalOwnerTransportSnapshotFromTransportForHome(
  _matrixHome: string,
  transport: JsonRecord | null,
): ILocalOwnerTransportSnapshot | undefined {
  return readLocalOwnerTransportSnapshotFromTransport(transport);
}

function readLocalOwnerTransportSnapshotFromTransport(transport: JsonRecord | null): ILocalOwnerTransportSnapshot | undefined {
  if (!transport) return undefined;
  if (
    optionalString(transport.routeKey)
    || optionalString(transport.publicNamespace)
    || optionalString(transport.spaceId)
  ) {
    return undefined;
  }
  const root = optionalString(transport.root);
  if (!root) return undefined;
  const nats = asRecord(transport.nats);
  if (!nats || optionalString(nats.credentialsRef)) return undefined;
  const mode = optionalString(nats.mode);
  if (mode !== 'embedded' && mode !== 'external') return undefined;
  const natsPort = positivePort(nats.port) ?? loopbackUrlPort(optionalString(nats.url));
  const natsWsPort = positivePort(nats.wsPort) ?? loopbackUrlPort(optionalString(nats.wsUrl));
  const maxPayloadBytes = positiveInteger(nats.maxPayloadBytes);
  if (!natsPort || !natsWsPort) return undefined;
  const natsUrl = mode === 'external'
    ? optionalString(nats.url) ?? `nats://127.0.0.1:${natsPort}`
    : undefined;
  const natsWsUrl = mode === 'external'
    ? optionalString(nats.wsUrl) ?? `ws://127.0.0.1:${natsWsPort}`
    : undefined;
  const authorityRoot = optionalString(transport.authorityRoot);
  return {
    root,
    ...(authorityRoot && authorityRoot !== root ? { authorityRoot } : {}),
    nats: {
      mode,
      ...(natsUrl ? { url: natsUrl } : {}),
      ...(natsWsUrl ? { wsUrl: natsWsUrl } : {}),
      port: natsPort,
      wsPort: natsWsPort,
      ...(maxPayloadBytes ? { maxPayloadBytes } : {}),
      dataDir: optionalString(nats.dataDir) ?? 'nats/host-default',
      pidFile: optionalString(nats.pidFile) ?? 'nats/host-default/nats-server.pid',
      ...(optionalString(nats.binaryPath) ? { binaryPath: optionalString(nats.binaryPath) } : {}),
    },
  };
}

export function readHiveCastLocalOwnerTransport(
  cwd: string,
  matrixHome?: string,
): IHiveCastLocalOwnerTransport | null {
  const paths = hiveCastLinkPaths(cwd, matrixHome);
  const config = readJsonFile(paths.hostConfigPath);
  const snapshot = readLocalOwnerTransportSnapshot(config)
    ?? readLocalOwnerTransportSnapshotForHome(paths.matrixHome, config)
    ?? captureLocalOwnerTransport(paths.matrixHome, config)
    ?? readLocalOwnerTransportSnapshotFromStatus(paths.matrixHome)
    ?? readLocalOwnerTransportSnapshotFromRuntimeRecords(paths.matrixHome);
  if (!snapshot) return null;
  return {
    root: snapshot.root,
    ...(snapshot.authorityRoot ? { authorityRoot: snapshot.authorityRoot } : {}),
  };
}

function positivePort(value: unknown): number | undefined {
  if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
    return undefined;
  }
  return value;
}

function positiveInteger(value: unknown): number | undefined {
  if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
    return undefined;
  }
  return value;
}

function loopbackUrlPort(raw: string | undefined): number | undefined {
  if (!raw) return undefined;
  try {
    const parsed = new URL(raw);
    if (!['127.0.0.1', 'localhost', '[::1]', '::1'].includes(parsed.hostname)) {
      return undefined;
    }
    const port = Number.parseInt(parsed.port, 10);
    return Number.isFinite(port) && port > 0 ? port : undefined;
  } catch {
    return undefined;
  }
}

function localDefaultRuntimeScope(matrixHome: string): string {
  return installRuntimeScope(matrixHome);
}

function activeDefaultRuntimeScope(matrixHome: string): string {
  return localDefaultRuntimeScope(matrixHome);
}

function defaultRuntimeIdsForScope(scope: string): Set<string> {
  return new Set(HIVECAST_DEFAULT_RUNTIME_KEYS.map((key) => `RUNTIME-HOST-${scope}-${key}`));
}

function isHiveCastDefaultRuntimeId(runtimeId: string): boolean {
  return runtimeId.startsWith('RUNTIME-HOST-')
    && HIVECAST_DEFAULT_RUNTIME_KEYS.some((key) => runtimeId.endsWith(`-${key}`));
}

function updateHiveCastDefaultRuntimePolicies(matrixHome: string, activeScope: string): void {
  const runtimesDir = path.join(matrixHome, 'runtimes');
  if (!fs.existsSync(runtimesDir)) return;
  const activeIds = defaultRuntimeIdsForScope(activeScope);
  for (const entry of fs.readdirSync(runtimesDir, { withFileTypes: true })) {
    if (!entry.isDirectory()) continue;
    const runtimeId = entry.name;
    if (!isHiveCastDefaultRuntimeId(runtimeId)) continue;
    const recordPath = path.join(runtimesDir, runtimeId, 'runtime.json');
    const record = readJsonFile(recordPath);
    if (!record) continue;
    const recordOwner = ownerForPath(recordPath);
    const active = activeIds.has(runtimeId);
    const nextRecord = {
      ...record,
      startup: active ? 'auto' : 'manual',
      restart: active ? 'always' : 'never',
      updatedAt: new Date().toISOString(),
      metadata: {
        ...(asRecord(record.metadata) ?? {}),
        hivecastDefaultRuntimePolicy: active ? 'active' : 'inactive',
        hivecastDefaultRuntimePolicyUpdatedAt: new Date().toISOString(),
      },
    };
    writePrivateJson(recordPath, nextRecord);
    alignOwnership(recordPath, recordOwner);
  }
}

export function saveHiveCastHostLink(options: ISaveHiveCastHostLinkOptions): {
  readonly record: IHiveCastHostLinkRecord;
  readonly paths: IHiveCastLinkPaths;
} {
  const paths = hiveCastLinkPaths(options.cwd, options.matrixHome);
  fs.mkdirSync(paths.matrixHome, { recursive: true });
  const homeOwner = ownerForPath(paths.matrixHome);
  fs.mkdirSync(paths.credentialsDir, { recursive: true });
  alignOwnership(paths.credentialsDir, homeOwner);

  writePrivateJson(paths.natsCredentialsPath, options.natsCredentials);
  alignOwnership(paths.natsCredentialsPath, homeOwner);
  writePrivateJson(paths.hostCredentialsPath, options.natsCredentials);
  alignOwnership(paths.hostCredentialsPath, homeOwner);
  const leafnodeUrl = optionalString(options.nats.leafnodeUrl);
  const leafnodeCredentialBody = natsUserCredentialsFile(options.natsCredentials);
  if (options.authorityCoordinator !== true && leafnodeUrl) {
    if (!leafnodeCredentialBody) {
      throw new Error('HIVECAST_LINK_LEAFNODE_CREDENTIALS_MISSING: linked Device leaf-node transport requires jwt+seed credentials');
    }
    writePrivateText(paths.natsLeafnodeCredentialsPath, leafnodeCredentialBody);
    alignOwnership(paths.natsLeafnodeCredentialsPath, homeOwner);
  } else {
    fs.rmSync(paths.natsLeafnodeCredentialsPath, { force: true });
  }
  if (options.hostLinkToken) {
    writePrivateText(paths.hostLinkTokenPath, `${options.hostLinkToken}\n`);
    alignOwnership(paths.hostLinkTokenPath, homeOwner);
  } else {
    fs.rmSync(paths.hostLinkTokenPath, { force: true });
  }

  const record: IHiveCastHostLinkRecord = {
    version: 1,
    cloudUrl: options.cloudUrl,
    ...(options.deviceRegistryRoot ? { deviceRegistryRoot: options.deviceRegistryRoot } : {}),
    ...(options.hostLinkId ? { hostLinkId: options.hostLinkId } : {}),
    ...(options.hostId ? { hostId: options.hostId } : {}),
    ...(options.principalId ? { principalId: options.principalId } : {}),
    ...(options.hostName ? { hostName: options.hostName } : {}),
    ...(options.deviceSlug ? { deviceSlug: options.deviceSlug } : {}),
    authorityCoordinator: options.authorityCoordinator === true,
    ...(options.spaceId ? { spaceId: options.spaceId } : {}),
    ...(options.routeKey ? { routeKey: options.routeKey } : {}),
    ...(options.publicNamespace ? { publicNamespace: options.publicNamespace } : {}),
    authorityRoot: options.authorityRoot,
    linkedAt: options.linkedAt ?? new Date().toISOString(),
    credentials: {
      ...(options.hostLinkToken ? { hostLinkTokenRef: 'file:credentials/hivecast-host-link-token' } : {}),
      natsCredentialRef: HIVECAST_NATS_JSON_CREDENTIAL_REF,
      ...(options.authorityCoordinator !== true && leafnodeUrl
        ? { natsLeafnodeCredentialRef: HIVECAST_NATS_LEAFNODE_CREDENTIAL_REF }
        : {}),
    },
  };
  writePrivateJson(paths.linkPath, record);
  alignOwnership(paths.linkPath, homeOwner);

  const existingHostConfig = readJsonFile(paths.hostConfigPath);
  const localOwnerTransport = readLocalOwnerTransportSnapshotForHome(paths.matrixHome, existingHostConfig)
    ?? captureLocalOwnerTransportFromCurrentNats(paths.matrixHome, existingHostConfig)
    ?? readLocalOwnerTransportSnapshotFromStatus(paths.matrixHome)
    ?? readLocalOwnerTransportSnapshotFromRuntimeRecords(paths.matrixHome)
    ?? captureLocalOwnerTransport(paths.matrixHome, existingHostConfig);
  const linkedAuthorityTransport: ILinkedAuthorityTransportSnapshot = {
    authorityRoot: options.authorityRoot,
    ...(options.routeKey ? { routeKey: options.routeKey } : {}),
    ...(options.publicNamespace ? { publicNamespace: options.publicNamespace } : {}),
    ...(options.spaceId ? { spaceId: options.spaceId } : {}),
    authorityCoordinator: options.authorityCoordinator === true,
    ...(options.authorityCoordinator !== true && leafnodeUrl
      ? { leafnode: { url: leafnodeUrl, credentialsRef: HIVECAST_NATS_LEAFNODE_CREDENTIAL_REF } }
      : {}),
    nats: linkedAuthorityNatsTransport(options.nats, paths.natsCredentialsPath),
  };
  const hostConfig = buildHostConfig(
    existingHostConfig,
    paths.matrixHome,
    localOwnerTransport,
    linkedAuthorityTransport,
  );
  assertLinkedHostConfigConverged(record, hostConfig);
  writePrivateJson(paths.hostConfigPath, hostConfig);
  alignOwnership(paths.hostConfigPath, homeOwner);
  updateHiveCastDefaultRuntimePolicies(paths.matrixHome, activeDefaultRuntimeScope(paths.matrixHome));

  return { record, paths };
}

export function readHiveCastHostLink(cwd: string, matrixHome?: string): {
  readonly record: IHiveCastHostLinkRecord | null;
  readonly paths: IHiveCastLinkPaths;
} {
  const paths = hiveCastLinkPaths(cwd, matrixHome);
  const parsed = readJsonFile(paths.linkPath);
  if (!parsed || parsed.version !== 1) {
    return { record: null, paths };
  }
  const authorityRoot = optionalString(parsed.authorityRoot);
  const cloudUrl = optionalString(parsed.cloudUrl);
  const credentials = asRecord(parsed.credentials);
  const natsCredentialRef = optionalString(credentials?.natsCredentialRef);
  const linkedAt = optionalString(parsed.linkedAt);
  if (!authorityRoot || !cloudUrl || !natsCredentialRef || !linkedAt) {
    return { record: null, paths };
  }
  const hostId = optionalString(parsed.hostId);
  const deviceRegistryRoot = optionalString(parsed.deviceRegistryRoot);
  const hostLinkId = optionalString(parsed.hostLinkId);
  const principalId = optionalString(parsed.principalId);
  const hostName = optionalString(parsed.hostName);
  const deviceSlug = optionalString(parsed.deviceSlug);
  const authorityCoordinator = typeof parsed.authorityCoordinator === 'boolean'
    ? parsed.authorityCoordinator
    : undefined;
  const spaceId = optionalString(parsed.spaceId);
  const routeKey = optionalString(parsed.routeKey);
  const publicNamespace = optionalString(parsed.publicNamespace);
  const hostLinkTokenRef = optionalString(credentials?.hostLinkTokenRef);
  const registryTokenRef = optionalString(credentials?.registryTokenRef);
  const natsLeafnodeCredentialRef = optionalString(credentials?.natsLeafnodeCredentialRef);
  return {
    paths,
    record: {
      version: 1,
      cloudUrl,
      ...(deviceRegistryRoot ? { deviceRegistryRoot } : {}),
      ...(hostLinkId ? { hostLinkId } : {}),
      ...(hostId ? { hostId } : {}),
      ...(principalId ? { principalId } : {}),
      ...(hostName ? { hostName } : {}),
      ...(deviceSlug ? { deviceSlug } : {}),
      ...(typeof authorityCoordinator === 'boolean' ? { authorityCoordinator } : {}),
      ...(spaceId ? { spaceId } : {}),
      ...(routeKey ? { routeKey } : {}),
      ...(publicNamespace ? { publicNamespace } : {}),
      authorityRoot,
      linkedAt,
      credentials: {
        natsCredentialRef,
        ...(hostLinkTokenRef ? { hostLinkTokenRef } : {}),
        ...(registryTokenRef ? { registryTokenRef } : {}),
        ...(natsLeafnodeCredentialRef ? { natsLeafnodeCredentialRef } : {}),
      },
    },
  };
}

export function removeHiveCastCredentialFiles(
  paths: Pick<IHiveCastLinkPaths, 'natsCredentialsPath' | 'natsLeafnodeCredentialsPath' | 'hostCredentialsPath' | 'hostLinkTokenPath'>,
): boolean {
  const existed = fs.existsSync(paths.natsCredentialsPath)
    || fs.existsSync(paths.natsLeafnodeCredentialsPath)
    || fs.existsSync(paths.hostCredentialsPath)
    || fs.existsSync(paths.hostLinkTokenPath);
  fs.rmSync(paths.natsCredentialsPath, { force: true });
  fs.rmSync(paths.natsLeafnodeCredentialsPath, { force: true });
  fs.rmSync(paths.hostCredentialsPath, { force: true });
  fs.rmSync(paths.hostLinkTokenPath, { force: true });
  return existed;
}

export function removeHiveCastHostLink(
  cwd: string,
  matrixHome?: string,
  options: IRemoveHiveCastHostLinkOptions = {},
): IRemoveHiveCastHostLinkResult {
  const paths = hiveCastLinkPaths(cwd, matrixHome);
  const existed = fs.existsSync(paths.linkPath)
    || fs.existsSync(paths.natsCredentialsPath)
    || fs.existsSync(paths.natsLeafnodeCredentialsPath)
    || fs.existsSync(paths.hostLinkTokenPath)
    || fs.existsSync(paths.hostCredentialsPath)
    || isHostConfigLinked(paths.hostConfigPath);
  fs.rmSync(paths.linkPath, { force: true });
  updateHiveCastDefaultRuntimePolicies(paths.matrixHome, localDefaultRuntimeScope(paths.matrixHome));
  const hostConfigReset = resetHostConfigToLocalOwner(paths.hostConfigPath);
  if (options.preserveCredentials !== true) {
    removeHiveCastCredentialFiles(paths);
  }
  return { removed: existed, hostConfigReset, paths };
}

export function readHiveCastLinkStatus(cwd: string, matrixHome?: string): IHiveCastLinkStatus {
  const { record, paths } = readHiveCastHostLink(cwd, matrixHome);
  const hostConfigLinked = Boolean(record) && fs.existsSync(paths.hostConfigPath);
  return {
    linked: Boolean(record),
    matrixHome: paths.matrixHome,
    linkPath: paths.linkPath,
    natsCredentialsPath: paths.natsCredentialsPath,
    hostConfigPath: paths.hostConfigPath,
    natsCredentialsPresent: fs.existsSync(paths.natsCredentialsPath),
    hostConfigPresent: fs.existsSync(paths.hostConfigPath),
    hostConfigLinked,
    ...(record?.hostLinkId ? { hostLinkId: record.hostLinkId } : {}),
    ...(record?.authorityRoot ? { authorityRoot: record.authorityRoot } : {}),
    ...(record?.routeKey ? { routeKey: record.routeKey } : {}),
    ...(record?.publicNamespace ? { publicNamespace: record.publicNamespace } : {}),
    ...(record?.spaceId ? { spaceId: record.spaceId } : {}),
    ...(typeof record?.authorityCoordinator === 'boolean' ? { authorityCoordinator: record.authorityCoordinator } : {}),
    ...(record?.cloudUrl ? { cloudUrl: record.cloudUrl } : {}),
    ...(record?.linkedAt ? { linkedAt: record.linkedAt } : {}),
  };
}

function isHostConfigLinked(hostConfigPath: string): boolean {
  const config = readJsonFile(hostConfigPath);
  const transport = asRecord(config?.transport);
  if (!transport) return false;
  const nats = asRecord(transport.nats);
  const root = optionalString(transport.root);
  const authorityRoot = optionalString(transport.authorityRoot);
  const matrixHome = optionalString(config?.home) ?? path.dirname(hostConfigPath);
  const localOwnerTransport = readLocalOwnerTransportSnapshotForHome(matrixHome, config);
  const localOwnerRoot = localOwnerTransport?.root;
  const hasCloudAuthority = Boolean(
    authorityRoot
      && authorityRoot !== root,
  ) && (localOwnerRoot ? authorityRoot !== localOwnerRoot : true);
  const externalNatsIsHiveCast = nats?.mode === 'external'
    && (
      Boolean(optionalString(nats.credentialsRef))
      || (!loopbackUrlPort(optionalString(nats.url)) && !loopbackUrlPort(optionalString(nats.wsUrl)))
    );
  return Boolean(
    optionalString(transport.routeKey)
      || optionalString(transport.publicNamespace)
      || optionalString(transport.spaceId)
      || hasCloudAuthority
      || externalNatsIsHiveCast,
  );
}

function resetHostConfigToLocalOwner(hostConfigPath: string): boolean {
  const config = readJsonFile(hostConfigPath);
  if (!config) return false;
  const transport = asRecord(config.transport);
  if (!transport) return false;

  const currentNats = asRecord(transport.nats);
  const matrixHome = optionalString(config.home) ?? path.dirname(hostConfigPath);
  const localOwnerTransport = readLocalOwnerTransportSnapshotForHome(matrixHome, config)
    ?? readLocalOwnerTransportSnapshotFromRuntimeRecords(matrixHome)
    ?? readLocalOwnerTransportSnapshotFromStatus(matrixHome);
  const nextTransport: JsonRecord = { ...transport };
  const localRoot = localOwnerAuthorityRoot(matrixHome);
  nextTransport.root = localOwnerTransport?.root ?? localRoot;
  if (localOwnerTransport?.authorityRoot) {
    nextTransport.authorityRoot = localOwnerTransport.authorityRoot;
  } else {
    delete nextTransport.authorityRoot;
  }
  nextTransport.addressRoot = localOwnerTransport?.root ?? localRoot;
  delete nextTransport.routeKey;
  delete nextTransport.publicNamespace;
  delete nextTransport.spaceId;
  nextTransport.nats = localOwnerTransport?.nats
    ?? (currentNats && currentNats.mode !== 'external' ? currentNats : defaultLocalOwnerNatsTransport());

  const nextConfig: JsonRecord = {
    ...config,
    transport: nextTransport,
  };
  delete nextConfig.natsTopology;
  writePrivateJson(hostConfigPath, nextConfig);
  return true;
}
