import {
  Controller,
  Post,
  Body,
  Logger,
  HttpException,
  HttpStatus,
  NotFoundException,
  UseGuards,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js';
import { scopeFromUser, type AuthenticatedUserLike } from '../auth/session-scope.js';
import { v4 as uuid } from 'uuid';
import { ChatRequestDto } from './chat.dto.js';
import { ChatRuntimeRouter } from './chat-runtime-router.js';
import { ownConversation } from './chat-runtime.js';
import type { LegacyRuntimeFailure } from './chat-runtime.js';

interface ChatResponse {
  conversationId: string;
  text: string;
}

@Controller('api/chat')
@UseGuards(AuthGuard)
export class ChatController {
  private readonly logger = new Logger(ChatController.name);

  constructor(private readonly runtime: ChatRuntimeRouter) {}

  @Post()
  @Throttle({ default: { limit: 10, ttl: 60_000 } })
  async chat(
    @Body() body: ChatRequestDto,
    @CurrentUser() user: AuthenticatedUserLike,
  ): Promise<ChatResponse> {
    const conversationId = body.conversationId ?? uuid();
    const scope = scopeFromUser(user);

    this.logger.debug(`Handling chat request for user=${user.id}, conversation=${conversationId}`);

    // The one exclusive runtime owns execution. In legacy mode this reaches the embedded runtime;
    // in pi-rpc it fails closed with `runtime_unsupported` before ever touching embedded execution.
    const result = await this.runtime.completeLegacyRestTurn(
      ownConversation(conversationId, scope),
      { content: body.content },
    );

    if (result.ok) {
      return { conversationId, text: result.value.text };
    }

    throw this.toHttpException(result, conversationId);
  }

  /** Maps a total {@link LegacyRuntimeFailure} to the fixed browser-safe HTTP surface. */
  private toHttpException(failure: LegacyRuntimeFailure, conversationId: string): HttpException {
    switch (failure.code) {
      case 'conversation_unavailable':
        return new NotFoundException('Session not found');
      case 'request_invalid':
      case 'thinking_level_invalid':
        return new HttpException('Invalid chat request', HttpStatus.BAD_REQUEST);
      case 'timeout':
        return new HttpException('Agent response timed out', HttpStatus.GATEWAY_TIMEOUT);
      case 'runtime_unsupported':
      case 'runtime_unavailable':
        return new HttpException('Agent runtime unavailable', HttpStatus.SERVICE_UNAVAILABLE);
      default:
        this.logger.error(`Chat turn failed for conversation=${conversationId}: ${failure.code}`);
        return new HttpException('Agent processing failed', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
