/**
 * Remote File System Surface
 *
 * Proxies all filesystem operations (read, write, list, stat, etc.)
 * to a remote node (e.g. Electron desktop app) via the WS control plane.
 * This allows the gateway to work with files on any connected device,
 * not just its own local filesystem.
 */
export class RemoteFileSystemSurface {
    id;
    ws;
    type = "remote-filesystem";
    _state = "idle";
    _sessionId = null;
    _startedAt = null;
    _projectRoot = null;
    _nodeId = null;
    _opCount = 0;
    /**
     * Backup map: file path → original content.
     * We store remote backups in memory on the gateway side so undo works.
     */
    _backups = new Map();
    onOutput;
    onStateChange;
    constructor(id, ws) {
        this.id = id;
        this.ws = ws;
    }
    get state() {
        return this._state;
    }
    get sessionId() {
        return this._sessionId;
    }
    get nodeId() {
        return this._nodeId;
    }
    async start(input) {
        this._sessionId = input.sessionId;
        this._startedAt = new Date().toISOString();
        this._projectRoot = input.projectRoot;
        this._nodeId = input.nodeId ?? null;
        this._setState("running");
    }
    async stop(_input) {
        this._setState("stopped");
    }
    snapshot() {
        return {
            id: this.id,
            type: this.type,
            state: this._state,
            sessionId: this._sessionId ?? "",
            startedAt: this._startedAt ?? undefined,
            metadata: {
                projectRoot: this._projectRoot,
                nodeId: this._nodeId,
                operationCount: this._opCount,
                remote: true,
            },
        };
    }
    // ── File Operations (all proxied to remote node) ──────────────
    async read(filePath) {
        this.ensureRunning();
        this._opCount++;
        const result = await this.ws.proxyFsOp(this._nodeId, "read", { path: filePath });
        this.onOutput?.(`read ${filePath} (${result.content.length} bytes)`);
        return result.content;
    }
    async write(filePath, content) {
        this.ensureRunning();
        this._opCount++;
        // Save backup of original content (only on first modification)
        if (!this._backups.has(filePath)) {
            try {
                const original = await this.read(filePath);
                this._backups.set(filePath, original);
            }
            catch {
                // File didn't exist before — backup is null (undo = delete)
                this._backups.set(filePath, null);
            }
        }
        await this.ws.proxyFsOp(this._nodeId, "write", { path: filePath, content });
        this.onOutput?.(`wrote ${filePath} (${content.length} bytes)`);
    }
    async patch(filePath, search, replace) {
        this.ensureRunning();
        this._opCount++;
        const original = await this.read(filePath);
        if (!original.includes(search)) {
            return { matched: false };
        }
        // Save backup before first modification
        if (!this._backups.has(filePath)) {
            this._backups.set(filePath, original);
        }
        const patched = original.replace(search, replace);
        await this.write(filePath, patched);
        this.onOutput?.(`patched ${filePath}`);
        return { matched: true };
    }
    async exists(filePath) {
        this.ensureRunning();
        try {
            const result = await this.ws.proxyFsOp(this._nodeId, "exists", { path: filePath });
            return result;
        }
        catch {
            return false;
        }
    }
    async list(dirPath) {
        this.ensureRunning();
        this._opCount++;
        const entries = await this.ws.proxyFsOp(this._nodeId, "list", { path: dirPath });
        return entries;
    }
    async statFile(filePath) {
        this.ensureRunning();
        return this.ws.proxyFsOp(this._nodeId, "stat", { path: filePath });
    }
    /** Check if a path is within project boundary (basic check for remote paths) */
    isPathAllowed(filePath) {
        if (!this._projectRoot)
            return false;
        // Normalize separators for cross-platform comparison
        const normRoot = this._projectRoot.replace(/\\/g, "/").toLowerCase();
        const normPath = filePath.replace(/\\/g, "/").toLowerCase();
        return normPath.startsWith(normRoot);
    }
    /**
     * Restore a file to its pre-modification state.
     */
    async restore(filePath) {
        this.ensureRunning();
        if (!this._backups.has(filePath))
            return false;
        const backup = this._backups.get(filePath);
        if (backup === null) {
            // File was newly created — we can't easily delete remotely yet
            // For now, just clear the backup
        }
        else {
            await this.write(filePath, backup);
        }
        this._backups.delete(filePath);
        this.onOutput?.(`restored ${filePath}`);
        return true;
    }
    hasBackup(filePath) {
        return this._backups.has(filePath);
    }
    getBackup(filePath) {
        if (!this._backups.has(filePath))
            return undefined;
        return this._backups.get(filePath) ?? null;
    }
    clearBackup(filePath) {
        this._backups.delete(filePath);
    }
    async saveExternalBackup(filePath) {
        this.ensureRunning();
        if (this._backups.has(filePath))
            return;
        try {
            const original = await this.read(filePath);
            this._backups.set(filePath, original);
        }
        catch {
            this._backups.set(filePath, null);
        }
    }
    ensureRunning() {
        if (this._state !== "running") {
            throw new Error("Remote FileSystem surface is not running");
        }
        if (!this._nodeId) {
            throw new Error("Remote FileSystem surface has no nodeId");
        }
    }
    _setState(s) {
        this._state = s;
        this.onStateChange?.(s);
    }
}
export class RemoteFileSystemSurfaceFactory {
    ws;
    type = "remote-filesystem";
    constructor(ws) {
        this.ws = ws;
    }
    create(id) {
        return new RemoteFileSystemSurface(id, this.ws);
    }
}
//# sourceMappingURL=remote-filesystem.js.map