import type { GatewayRequest, OutboundMessage } from '../protocol.js';
import { makeResponse, makeError, ErrorCode } from '../protocol.js';
import type { SessionManager } from '../../session/manager.js';
import type { SessionBridge } from '../session-bridge.js';

export interface SessionHandlerDeps {
  sessionManager: SessionManager;
  sessionBridge?: SessionBridge;
}

export function createSessionHandlers(deps: SessionHandlerDeps) {
  return {
    'sessions.list': async (request: GatewayRequest): Promise<OutboundMessage> => {
      const sessionIds = deps.sessionManager.listSessions();
      const sessions = sessionIds.map(id => ({
        id,
        messageCount: deps.sessionManager.getSession(
          id.split(':')[0],
          id.split(':').slice(1).join(':'),
        ).getHistory().length,
      }));
      return makeResponse(request.id, { sessions });
    },

    'sessions.history': async (request: GatewayRequest): Promise<OutboundMessage> => {
      const params = request.params as { sessionId?: string; limit?: number; offset?: number } | undefined;
      if (!params?.sessionId) {
        return makeError(request.id, ErrorCode.InvalidRequest, 'sessionId is required');
      }

      const { sessionId, limit, offset } = params;
      const parts = sessionId.split(':');
      const frontend = parts[0];
      const userId = parts.slice(1).join(':');
      const session = deps.sessionManager.getSession(frontend, userId);
      const allMessages = session.getHistory();

      const start = offset ?? 0;
      const end = limit ? start + limit : allMessages.length;
      const messages = allMessages.slice(start, end);

      return makeResponse(request.id, {
        messages,
        total: allMessages.length,
      });
    },

    'sessions.create': async (request: GatewayRequest): Promise<OutboundMessage> => {
      const params = request.params as { sessionId?: string } | undefined;
      const sessionId = params?.sessionId ?? `ws:${Date.now()}`;
      const parts = sessionId.split(':');
      const frontend = parts[0];
      const userId = parts.slice(1).join(':');

      // Creating a session via getSession is idempotent
      deps.sessionManager.getSession(frontend, userId);

      return makeResponse(request.id, { sessionId });
    },

    'sessions.delete': async (request: GatewayRequest): Promise<OutboundMessage> => {
      const params = request.params as { sessionId?: string } | undefined;
      if (!params?.sessionId) {
        return makeError(request.id, ErrorCode.InvalidRequest, 'sessionId is required');
      }

      const { sessionId } = params;
      const parts = sessionId.split(':');
      const frontend = parts[0];
      const userId = parts.slice(1).join(':');
      const session = deps.sessionManager.getSession(frontend, userId);
      session.clear();

      return makeResponse(request.id, { deleted: true, sessionId });
    },

    'sessions.switch': async (request: GatewayRequest): Promise<OutboundMessage> => {
      const params = request.params as { sessionId?: string; connectionId?: string } | undefined;
      if (!params?.sessionId) {
        return makeError(request.id, ErrorCode.InvalidRequest, 'sessionId is required');
      }
      if (!deps.sessionBridge) {
        return makeError(request.id, ErrorCode.InternalError, 'Session switching not available');
      }

      const connectionId = params.connectionId as string;
      if (!connectionId) {
        return makeError(request.id, ErrorCode.InvalidRequest, 'connectionId is required');
      }

      try {
        deps.sessionBridge.switchSession(connectionId, params.sessionId);
        return makeResponse(request.id, { switched: true, sessionId: params.sessionId });
      } catch (err) {
        const message = err instanceof Error ? err.message : 'Failed to switch session';
        return makeError(request.id, ErrorCode.InternalError, message);
      }
    },
  };
}
