/**
 * Context Routes
 *
 * Session context management endpoints.
 */

import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import type { AppContext } from '../router.js';
import { ContextUpdateRequestSchema, ContextQuerySchema } from '../types.js';
import { ContextService } from '../../context/service.js';

export const contextRoutes = new Hono<AppContext>();

/**
 * Helper to get context service
 */
function getContextService(c: { get: (key: string) => unknown }): ContextService | null {
  const conn = c.get('conn');
  const repoRoot = c.get('repoRoot') as string | undefined;

  if (!conn) {
    return null;
  }

  return new ContextService({
    conn: conn as Parameters<typeof ContextService['prototype']['constructor']>[0]['conn'],
    repoRoot,
  });
}

/**
 * GET /context - Get current session context
 */
contextRoutes.get('/', zValidator('query', ContextQuerySchema), async (c) => {
  const service = getContextService(c);
  const query = c.req.valid('query');

  if (!service) {
    return c.json({ error: 'No database connection' }, 500);
  }

  try {
    const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();
    const items = await service.getContext(terminalId, {
      query: query.query,
      minScore: query.minScore,
      maxItems: query.maxItems,
      rerank: query.rerank,
    });

    return c.json({
      terminalId,
      items: items.map((item) => ({
        qualifiedName: item.qualifiedName,
        entityType: item.entityType,
        filePath: item.filePath,
        score: item.score,
        description: item.description,
        source: item.source,
      })),
      total: items.length,
    });
  } catch (error) {
    return c.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});

/**
 * GET /context/prompt - Get context formatted for LLM prompt
 */
contextRoutes.get('/prompt', zValidator('query', ContextQuerySchema), async (c) => {
  const service = getContextService(c);
  const query = c.req.valid('query');

  if (!service) {
    return c.json({ error: 'No database connection' }, 500);
  }

  try {
    const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();
    const prompt = await service.getContextPrompt(terminalId, {
      query: query.query,
      minScore: query.minScore,
      maxItems: query.maxItems,
      rerank: query.rerank,
    });

    return c.json({
      terminalId,
      prompt,
    });
  } catch (error) {
    return c.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});

/**
 * POST /context/update - Update session context
 */
contextRoutes.post(
  '/update',
  zValidator('json', ContextUpdateRequestSchema),
  async (c) => {
    const service = getContextService(c);
    const body = c.req.valid('json');

    if (!service) {
      return c.json({ error: 'No database connection' }, 500);
    }

    try {
      const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();

      await service.updateContext(terminalId, {
        explorationSteps: body.explorationSteps,
        modifiedFiles: body.modifiedFiles,
      });

      // Return updated context
      const items = await service.getContext(terminalId);

      return c.json({
        success: true,
        terminalId,
        itemCount: items.length,
      });
    } catch (error) {
      return c.json(
        { error: error instanceof Error ? error.message : 'Unknown error' },
        500
      );
    }
  }
);

/**
 * POST /context/exploration - Record exploration steps
 */
contextRoutes.post('/exploration', async (c) => {
  const service = getContextService(c);

  if (!service) {
    return c.json({ error: 'No database connection' }, 500);
  }

  try {
    const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();
    const body = await c.req.json<{
      steps: Array<{ toolName: string; entitiesDiscovered: string[] }>;
    }>();

    if (!body.steps || !Array.isArray(body.steps)) {
      return c.json({ error: 'steps array is required' }, 400);
    }

    await service.recordExploration(terminalId, body.steps);

    return c.json({
      success: true,
      terminalId,
      stepsRecorded: body.steps.length,
    });
  } catch (error) {
    return c.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});

/**
 * POST /context/modifications - Record file modifications
 */
contextRoutes.post('/modifications', async (c) => {
  const service = getContextService(c);

  if (!service) {
    return c.json({ error: 'No database connection' }, 500);
  }

  try {
    const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();
    const body = await c.req.json<{ files: string[] }>();

    if (!body.files || !Array.isArray(body.files)) {
      return c.json({ error: 'files array is required' }, 400);
    }

    await service.recordModifications(terminalId, body.files);

    return c.json({
      success: true,
      terminalId,
      filesRecorded: body.files.length,
    });
  } catch (error) {
    return c.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});

/**
 * DELETE /context - Clear session context
 */
contextRoutes.delete('/', async (c) => {
  const service = getContextService(c);

  if (!service) {
    return c.json({ error: 'No database connection' }, 500);
  }

  try {
    const terminalId = c.req.header('X-Terminal-Id') ?? service.getTerminalId();
    await service.clearContext(terminalId);

    return c.json({
      success: true,
      terminalId,
      message: 'Context cleared',
    });
  } catch (error) {
    return c.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});
