import { RelayCast } from '@relaycast/sdk';
import { ActionRegistry } from './actions/index.js';
import { relaycastTelemetryOptions, relaycastWorkspaceTelemetryOptions, } from './relaycast-telemetry.js';
import { RelaycastMessagingClient, } from './messaging/index.js';
import { createEnrichedMessages, createWorkspaceFacade, registerFacadeAction, resolveAgentToken, } from './facade.js';
import { createAgentHandle, createListenerHub, } from './listeners.js';
export class AgentRelay {
    messaging;
    actions;
    workspaceKey;
    messagingOptions;
    clientsByToken = new Map();
    createAgentMessaging;
    enrichedMessages;
    workspaceFacade;
    hub;
    constructor(options = {}) {
        const { messaging, actions, workspaceKey, createAgentMessaging, ...messagingOptions } = options;
        const resolvedWorkspaceKey = workspaceKey ?? messagingOptions.apiKey;
        this.workspaceKey = resolvedWorkspaceKey;
        this.messagingOptions = { ...messagingOptions, workspaceKey: resolvedWorkspaceKey };
        this.messaging = messaging ?? new RelaycastMessagingClient(this.messagingOptions);
        this.actions = actions ?? new ActionRegistry();
        this.createAgentMessaging =
            createAgentMessaging ??
                ((token) => new RelaycastMessagingClient({ ...this.messagingOptions, agentToken: token }));
    }
    static async createWorkspace(input) {
        const options = typeof input === 'string' ? { name: input } : input;
        const telemetry = relaycastTelemetryOptions(options);
        const workspace = (await RelayCast.createWorkspace(options.name, {
            baseUrl: options.baseUrl,
            ...relaycastWorkspaceTelemetryOptions(options),
        }));
        const workspaceKey = extractWorkspaceKey(workspace);
        if (!workspaceKey) {
            throw new Error('Workspace created, but the response did not include a workspace key.');
        }
        return new AgentRelay({
            workspaceKey,
            baseUrl: options.baseUrl,
            retryPolicy: options.retryPolicy,
            actions: options.actions,
            ...telemetry,
        });
    }
    get agents() {
        return this.messaging.agents;
    }
    get channels() {
        return this.messaging.channels;
    }
    get messages() {
        if (!this.enrichedMessages) {
            this.enrichedMessages = createEnrichedMessages(this.messaging.messages, this.createMessagingResolver());
        }
        return this.enrichedMessages;
    }
    get threads() {
        return this.messaging.threads;
    }
    get inbox() {
        return this.messaging.inbox;
    }
    get events() {
        return this.listenerHub.events;
    }
    get listenerHub() {
        if (!this.hub) {
            this.hub = createListenerHub(this.messaging.events, this.actions);
        }
        return this.hub;
    }
    get deliveries() {
        return this.messaging.deliveries;
    }
    get integrations() {
        return this.messaging.integrations;
    }
    get webhooks() {
        return this.messaging.webhooks;
    }
    get capabilities() {
        return this.messaging.commands;
    }
    get workspace() {
        if (!this.workspaceFacade) {
            this.workspaceFacade = createWorkspaceFacade(this.messaging, {
                buildAgentClient: (registration) => this.buildAgentClient(registration),
                reconnectAgent: (apiToken) => this.reconnectAgent(apiToken),
            });
        }
        return this.workspaceFacade;
    }
    /** Build a live client bound to a freshly-registered agent. */
    buildAgentClient(registration) {
        return assembleAgentClient(this.messagingForToken(registration.token), this.actions, {
            id: registration.id,
            name: registration.name,
            token: registration.token,
        });
    }
    /** Rehydrate a live client from a persisted agent token, resolving identity from the relay. */
    async reconnectAgent(apiToken) {
        const messaging = this.messagingForToken(apiToken);
        const identity = await messaging.agents.me();
        return assembleAgentClient(messaging, this.actions, {
            id: identity.id,
            name: identity.name,
            token: apiToken,
        });
    }
    registerAction(def) {
        // The workspace-scoped client has no single handler-agent identity or
        // agent connection, so relay wiring is skipped and the action stays
        // in-process. Use an agent client (workspace.register / reconnect) to
        // register a relay-routed action.
        return registerFacadeAction(this.actions, def, { messaging: this.messaging });
    }
    /** Subscribe by dotted event name, `'*'`/prefix wildcard, or a predicate. */
    addListener(selector, handler) {
        return this.listenerHub.addListener(selector, handler);
    }
    action(name) {
        return this.listenerHub.action(name);
    }
    agent(input) {
        return this.listenerHub.agent(input);
    }
    emitSessionEvent(agentId, event) {
        this.listenerHub.emitSessionEvent(agentId, event);
    }
    messagingForToken(token) {
        let client = this.clientsByToken.get(token);
        if (!client) {
            client = this.createAgentMessaging(token);
            this.clientsByToken.set(token, client);
        }
        return client;
    }
    createMessagingResolver() {
        return (from) => {
            const token = resolveAgentToken(from);
            return token ? this.messagingForToken(token).messages : this.messaging.messages;
        };
    }
}
function extractWorkspaceKey(payload) {
    const data = payload.data && typeof payload.data === 'object' ? payload.data : {};
    const value = payload.workspaceKey ??
        payload.workspace_key ??
        payload.apiKey ??
        payload.api_key ??
        data.workspaceKey ??
        data.workspace_key ??
        data.apiKey ??
        data.api_key;
    return typeof value === 'string' && value.trim() ? value : undefined;
}
export function agentRelayAgent(messaging, actions, handlerAgent) {
    // An acting-as agent client sends through its own token; `from` overrides are
    // best-effort and fall back to this client.
    const messages = createEnrichedMessages(messaging.messages, () => messaging.messages);
    const hub = createListenerHub(messaging.events, actions);
    return {
        messaging,
        agents: messaging.agents,
        channels: messaging.channels,
        messages,
        threads: messaging.threads,
        inbox: messaging.inbox,
        events: hub.events,
        deliveries: messaging.deliveries,
        integrations: messaging.integrations,
        webhooks: messaging.webhooks,
        capabilities: messaging.commands,
        workspace: createWorkspaceFacade(messaging),
        registerAction: (def) => registerFacadeAction(actions, def, { messaging, handlerAgent }),
        addListener: (selector, handler) => hub.addListener(selector, handler),
        action: (name) => hub.action(name),
        agent: (input) => hub.agent(input),
        emitSessionEvent: (agentId, event) => hub.emitSessionEvent(agentId, event),
    };
}
/**
 * Assemble a live agent client: an agent-scoped messaging surface plus the
 * agent's identity and status/tool predicate builders, with `reply`/`react`
 * convenience keyed on `messageId`.
 */
export function assembleAgentClient(messaging, actions, identity) {
    const base = agentRelayAgent(messaging, actions, identity.name);
    const handle = createAgentHandle(identity);
    return {
        ...base,
        ...handle,
        sendMessage: (input) => base.messages.send(input),
        reply: (input) => base.messages.reply(input),
        react: (input) => base.messages.react(input.messageId, input.emoji),
    };
}
//# sourceMappingURL=agent-relay.js.map