/**
 * CollabManager — orchestrates the full collaboration lifecycle.
 *
 * Pure app-layer class with no shell/TUI dependencies. Manages:
 * - CollabClient connection and room lifecycle
 * - CollabSync (CRDT workbook sync)
 * - CollabAwareness (peer sheet info broadcasting)
 * - Display name resolution
 *
 * Used by the interactive shell (/collab command), RPC mode, and tests.
 */
import { CollabAwareness } from './awareness.js';
import { CollabClient } from './collab-client.js';
import { CollabSync } from './collab-sync.js';
// ── File-based display name provider ───────────────────────────────────
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
const ADJECTIVES = [
    'brave',
    'calm',
    'eager',
    'fast',
    'happy',
    'keen',
    'quick',
    'sharp',
    'bold',
    'cool',
    'fierce',
    'witty',
    'swift',
    'wise',
    'bright',
    'chill'
];
const ANIMALS = [
    'otter',
    'fox',
    'hawk',
    'wolf',
    'bear',
    'lynx',
    'crow',
    'hare',
    'puma',
    'owl',
    'stag',
    'wren',
    'seal',
    'vole',
    'dove',
    'elk'
];
function randomName() {
    const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
    const animal = ANIMALS[Math.floor(Math.random() * ANIMALS.length)];
    const num = Math.floor(Math.random() * 100);
    return `${adj}-${animal}-${num}`;
}
/** Persists display name to `<agentDir>/collab.json`. */
export class FileDisplayNameProvider {
    agentDir;
    constructor(agentDir) {
        this.agentDir = agentDir;
    }
    getOrCreate() {
        const config = this.load();
        if (config.displayName)
            return { name: config.displayName, isNew: false };
        const name = randomName();
        this.save({ ...config, displayName: name });
        return { name, isNew: true };
    }
    set(name) {
        this.save({ ...this.load(), displayName: name });
    }
    get() {
        return this.load().displayName;
    }
    configPath() {
        return join(this.agentDir, 'collab.json');
    }
    load() {
        const path = this.configPath();
        if (!existsSync(path))
            return {};
        try {
            return JSON.parse(readFileSync(path, 'utf-8'));
        }
        catch {
            return {};
        }
    }
    save(config) {
        mkdirSync(this.agentDir, { recursive: true });
        writeFileSync(this.configPath(), JSON.stringify(config, null, 2) + '\n');
    }
}
/** Simple in-memory provider for tests. */
export class StaticDisplayNameProvider {
    name;
    constructor(name) {
        this.name = name;
    }
    getOrCreate() {
        return { name: this.name, isNew: false };
    }
    set(name) {
        this.name = name;
    }
    get() {
        return this.name;
    }
}
// ── CollabManager ──────────────────────────────────────────────────────
export class CollabManager {
    serverUrl;
    pool;
    displayNameProvider;
    _client;
    _sync = null;
    _awareness = null;
    constructor(serverUrl, pool, displayNameProvider) {
        this.serverUrl = serverUrl;
        this.pool = pool;
        this.displayNameProvider = displayNameProvider;
        this._client = new CollabClient(serverUrl);
    }
    /** The underlying CollabClient (for event wiring by modes). */
    get client() {
        return this._client;
    }
    get sync() {
        return this._sync;
    }
    get awareness() {
        return this._awareness;
    }
    // ── Room lifecycle ───────────────────────────────────────────────────
    /** Create a new room and auto-join it. Returns the join result. */
    async createRoom(displayName) {
        const name = displayName ?? this.displayNameProvider.getOrCreate().name;
        const roomId = await this._client.createRoom();
        const result = await this._client.joinRoom(roomId, name);
        this.attachSync();
        this.attachAwareness();
        return result;
    }
    /** Join an existing room by ID. Returns the join result. */
    async joinRoom(roomId, displayName) {
        const name = displayName ?? this.displayNameProvider.getOrCreate().name;
        const result = await this._client.joinRoom(roomId, name);
        this.attachSync();
        this.attachAwareness();
        return result;
    }
    /** Leave the current room and clean up sync/awareness. */
    leave() {
        this.detachSync();
        this.detachAwareness();
        this._client.leave();
    }
    /** Current collab status. */
    getStatus() {
        const { roomId, peerId, peers, connected } = this._client.state;
        return {
            connected,
            roomId,
            peerId,
            peers: [...peers.values()]
        };
    }
    /** Whether we're currently in a room. */
    get inRoom() {
        return this._client.state.roomId !== null;
    }
    // ── Display name ─────────────────────────────────────────────────────
    getDisplayName() {
        return this.displayNameProvider.getOrCreate();
    }
    setDisplayName(name) {
        this.displayNameProvider.set(name);
    }
    currentDisplayName() {
        return this.displayNameProvider.get();
    }
    // ── Cleanup ──────────────────────────────────────────────────────────
    destroy() {
        this.detachSync();
        this.detachAwareness();
        this._client.destroy();
    }
    // ── Private ──────────────────────────────────────────────────────────
    attachSync() {
        this._sync = new CollabSync(this._client, this.pool);
        void this._sync.startSyncing();
    }
    detachSync() {
        if (this._sync) {
            this._sync.destroy();
            this._sync = null;
        }
    }
    attachAwareness() {
        const activeWb = this.pool.activeWorkbookName;
        if (!activeWb)
            return;
        const wb = this.pool.getWorkbook(activeWb);
        this._awareness = new CollabAwareness(wb, this._client);
    }
    detachAwareness() {
        if (this._awareness) {
            this._awareness.destroy();
            this._awareness = null;
        }
    }
}
//# sourceMappingURL=collab-manager.js.map