/**
 * Runtime daemon registry service.
 *
 * Owns the domain behavior for recording known workspaces and the one live
 * local control-plane server. Workspace records are identity/catalog facts;
 * server liveness is top-level process state and must not be stored as
 * workspace ownership.
 */
import { resolve } from 'node:path';
import { DaemonRegistryReadSchema } from './schemas.js';
import { FileDaemonRegistryRepository } from './registry-repository.js';
export class RuntimeDaemonRegistryService {
    static read(registryPath) {
        const repository = new FileDaemonRegistryRepository({ registryPath });
        return RuntimeDaemonRegistryService.normalizeRegistry(repository.readRaw());
    }
    static registerLiveServer(input) {
        const registry = RuntimeDaemonRegistryService.read(input.registryPath);
        const now = input.server.lastSeenAt ?? new Date().toISOString();
        return RuntimeDaemonRegistryService.saveNext(input.registryPath, {
            version: 1,
            updatedAt: now,
            server: {
                ...input.server,
                lastSeenAt: now,
            },
            workspaces: registry.workspaces,
        });
    }
    static clearLiveServer(input) {
        const registry = RuntimeDaemonRegistryService.read(input.registryPath);
        const now = new Date().toISOString();
        const server = registry.server?.serverId === input.serverId ? undefined : registry.server;
        return RuntimeDaemonRegistryService.saveNext(input.registryPath, {
            version: 1,
            updatedAt: now,
            server,
            workspaces: registry.workspaces,
        });
    }
    static readWorkspaceRegistration(registryPath, workspaceId, stateRoot) {
        const registry = RuntimeDaemonRegistryService.read(registryPath);
        const normalizedStateRoot = stateRoot ? resolve(stateRoot) : undefined;
        return registry.workspaces.find((record) => (normalizedStateRoot ?
            resolve(record.workspace.stateRoot) === normalizedStateRoot
            : record.workspace.id === workspaceId)) ?? null;
    }
    static registerKnownWorkspaces(input) {
        const registryPath = input.registryPath ?? FileDaemonRegistryRepository.resolvePath();
        const registry = RuntimeDaemonRegistryService.read(registryPath);
        const now = new Date().toISOString();
        const nextRecords = RuntimeDaemonRegistryService.toRecordMap(registry.workspaces);
        for (const workspace of input.workspaces) {
            nextRecords.set(RuntimeDaemonRegistryService.workspaceRecordKey(workspace), {
                workspace,
                updatedAt: now,
            });
        }
        return RuntimeDaemonRegistryService.saveNext(registryPath, {
            version: 1,
            updatedAt: now,
            server: registry.server,
            workspaces: Array.from(nextRecords.values()),
        });
    }
    static saveNext(registryPath, registry) {
        new FileDaemonRegistryRepository({ registryPath }).save(registry);
        return registry;
    }
    static createEmptyRegistry() {
        return {
            version: 1,
            updatedAt: new Date(0).toISOString(),
            workspaces: [],
        };
    }
    static normalizeRegistry(raw) {
        if (raw === undefined) {
            return RuntimeDaemonRegistryService.createEmptyRegistry();
        }
        const parsed = DaemonRegistryReadSchema.safeParse(raw);
        if (!parsed.success) {
            return RuntimeDaemonRegistryService.createEmptyRegistry();
        }
        return {
            version: 1,
            updatedAt: parsed.data.updatedAt?.trim() || new Date().toISOString(),
            server: RuntimeDaemonRegistryService.normalizeServer(parsed.data.server)
                ?? RuntimeDaemonRegistryService.normalizeLegacyServer(parsed.data.workspaces ?? []),
            workspaces: (parsed.data.workspaces ?? []).flatMap((record) => (record.workspace ? [RuntimeDaemonRegistryService.normalizeWorkspaceRecord(record)] : [])),
        };
    }
    static normalizeWorkspaceRecord(record) {
        return {
            workspace: record.workspace,
            updatedAt: record.updatedAt?.trim() || new Date().toISOString(),
        };
    }
    static normalizeServer(server) {
        if (!server?.serverId || !server.mode || !server.host || typeof server.port !== 'number' || !server.startedAt || !server.lastSeenAt) {
            return undefined;
        }
        return {
            serverId: server.serverId,
            mode: server.mode,
            host: server.host,
            port: server.port,
            pid: typeof server.pid === 'number' ? server.pid : 0,
            startedAt: server.startedAt,
            lastSeenAt: server.lastSeenAt,
        };
    }
    static normalizeLegacyServer(records) {
        return records
            .map((record) => record.owner)
            .filter((owner) => Boolean(owner))
            .sort((left, right) => (right.lastSeenAt ?? '').localeCompare(left.lastSeenAt ?? ''))
            .flatMap((owner) => RuntimeDaemonRegistryService.normalizeServer({
            serverId: owner.ownerId,
            mode: 'daemon',
            host: owner.host,
            port: owner.port,
            pid: owner.pid,
            startedAt: owner.startedAt,
            lastSeenAt: owner.lastSeenAt,
        }) ?? [])[0];
    }
    static toRecordMap(records) {
        return new Map(records.map((record) => [
            RuntimeDaemonRegistryService.workspaceRecordKey(record.workspace),
            record,
        ]));
    }
    static workspaceRecordKey(workspace) {
        return resolve(workspace.stateRoot);
    }
}
//# sourceMappingURL=registry-service.js.map