/**
 * Unified session messages endpoint (PilotDeck-only).
 *
 * GET /api/sessions/:sessionId/messages?projectName=&projectPath=&limit=&offset=
 *
 * Reads transcripts through the gateway's `readSessionMessages` RPC.
 * Previously this route imported `readWebSessionMessages` directly from
 * `dist/src/web/server/` — that coupled `ui/server/` to compiled
 * artifacts and meant `src/` edits were silently invisible until a
 * `npm run build`. Going through the gateway WebSocket means the
 * standalone `pilotdeck server` process owns the read path and we pick
 * up its in-flight session writes automatically.
 *
 * @module routes/messages
 */

import express from 'express';
import { getPilotDeckGateway } from '../pilotdeck-bridge.js';
import { createNormalizedMessage } from '../pilotdeck-message.js';

const router = express.Router();
const REPO_ROOT = process.cwd();

router.get('/:sessionId/messages', async (req, res) => {
  try {
    const { sessionId } = req.params;
    const projectPath = String(req.query.projectPath || req.query.projectName || REPO_ROOT);
    const limitParam = req.query.limit;
    const limit = limitParam !== undefined && limitParam !== null && limitParam !== ''
      ? parseInt(limitParam, 10)
      : null;
    const offset = parseInt(req.query.offset || '0', 10);

    const gateway = await getPilotDeckGateway();
    const result = await gateway.readSessionMessages({
      sessionKey: sessionId,
      projectKey: projectPath,
      limit: limit ?? undefined,
      cursor: offset > 0 ? String(offset) : undefined,
    });

    const messages = result.messages.map((message) => mapWebMessageToNormalized(message, sessionId));
    const totalKnown = typeof result.total === 'number' ? result.total : messages.length + offset;
    const hasMore = result.nextCursor !== undefined && result.nextCursor !== null;

    return res.json({
      messages,
      total: totalKnown,
      hasMore,
      offset,
      limit,
    });
  } catch (error) {
    console.error('[messages] read_session_messages failed:', error);
    return res.json({ messages: [], total: 0, hasMore: false, offset: 0, limit: null });
  }
});

function mapWebMessageToNormalized(message, sessionId) {
  const base = {
    id: message.id,
    sessionId,
    timestamp: message.createdAt,
    provider: message.provider || 'pilotdeck',
  };
  switch (message.kind) {
    case 'text':
      return createNormalizedMessage({
        ...base,
        kind: 'text',
        role: message.role === 'user' ? 'user' : 'assistant',
        content: message.text || '',
        ...(Array.isArray(message.images) && message.images.length > 0
          ? { images: message.images.map((image) => image?.data).filter(Boolean) }
          : {}),
      });
    case 'thinking':
      return createNormalizedMessage({ ...base, kind: 'thinking', content: message.text || '' });
    case 'tool_use':
      return createNormalizedMessage({
        ...base,
        kind: 'tool_use',
        toolName: message.toolName,
        toolInput: message.payload,
        toolId: message.toolCallId,
      });
    case 'tool_result': {
      const planPayload = message.payload && typeof message.payload === 'object'
          ? message.payload
          : {};
      return createNormalizedMessage({
        ...base,
        kind: 'tool_result',
        toolId: message.toolCallId,
        content: message.text || '',
        isError: message.ok === false,
        ...(message.errorCode ? { errorCode: message.errorCode } : {}),
        // Inline tool-result images (e.g. read_file on a PNG). The web
        // server already wraps the bare base64 from canonical messages as
        // data URLs in `toWebMessageImage`, so just pass them through.
        ...(Array.isArray(message.images) && message.images.length > 0
          ? {
              toolResultImages: message.images
                .filter((image) => image && typeof image.data === 'string')
                .map((image) => ({ data: image.data, mimeType: image.mimeType })),
            }
          : {}),
        ...(planPayload.planFilePath ? {
            planFilePath: planPayload.planFilePath,
            planTitle: planPayload.planTitle,
            planSummary: planPayload.planSummary,
        } : {}),
      });
    }
    case 'permission_request':
      return createNormalizedMessage({
        ...base,
        kind: 'permission_request',
        requestId: message.requestId,
        toolName: message.toolName,
        input: message.payload,
      });
    case 'elicitation_request':
      return createNormalizedMessage({
        ...base,
        kind: 'interactive_prompt',
        requestId: message.requestId,
        content: '',
      });
    case 'structured_output':
      return createNormalizedMessage({
        ...base,
        kind: 'status',
        text: 'structured',
        payload: message.payload,
      });
    case 'status':
      return createNormalizedMessage({ ...base, kind: 'status', text: message.text || '' });
    case 'complete':
      return createNormalizedMessage({ ...base, kind: 'complete' });
    case 'error':
      return createNormalizedMessage({ ...base, kind: 'error', content: message.text || '' });
    case 'interrupted':
      return createNormalizedMessage({ ...base, kind: 'interrupted', content: message.text || '' });
    case 'compact_boundary': {
      const payload = message.payload || {};
      return createNormalizedMessage({
        ...base,
        kind: 'compact_boundary',
        trigger: payload.trigger || 'auto',
        preTokens: payload.preTokens,
        compactLevel: payload.level,
        compactStage: payload.stage,
        compactStageLabel: payload.stageLabel || payload.stage,
        compactMetadata: payload,
      });
    }
    default:
      return createNormalizedMessage({ ...base, kind: 'status', text: message.kind });
  }
}

export default router;
