import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  ForbiddenException,
  Get,
  HttpCode,
  HttpStatus,
  Inject,
  NotFoundException,
  Param,
  Patch,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js';
import {
  CreateConversationDto,
  UpdateConversationDto,
  SendMessageDto,
  SearchMessagesDto,
} from './conversations.dto.js';

@Controller('api/conversations')
@UseGuards(AuthGuard)
export class ConversationsController {
  constructor(@Inject(BRAIN) private readonly brain: Brain) {}

  @Get()
  async list(@CurrentUser() user: { id: string }) {
    return this.brain.conversations.findAll(user.id);
  }

  @Get('search')
  async search(@Query() dto: SearchMessagesDto, @CurrentUser() user: { id: string }) {
    if (!dto.q || dto.q.trim().length === 0) {
      throw new BadRequestException('Query parameter "q" is required and must not be empty');
    }
    const limit = dto.limit ?? 20;
    const offset = dto.offset ?? 0;
    return this.brain.conversations.searchMessages(user.id, dto.q.trim(), limit, offset);
  }

  @Get(':id')
  async findOne(@Param('id') id: string, @CurrentUser() user: { id: string }) {
    const conversation = await this.brain.conversations.findById(id, user.id);
    if (!conversation) throw new NotFoundException('Conversation not found');
    return conversation;
  }

  @Post()
  async create(@CurrentUser() user: { id: string }, @Body() dto: CreateConversationDto) {
    return this.brain.conversations.create({
      userId: user.id,
      title: dto.title,
      projectId: dto.projectId,
    });
  }

  @Patch(':id')
  async update(
    @Param('id') id: string,
    @Body() dto: UpdateConversationDto,
    @CurrentUser() user: { id: string },
  ) {
    const conversation = await this.brain.conversations.update(id, user.id, dto);
    if (!conversation) throw new NotFoundException('Conversation not found');
    return conversation;
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  async remove(@Param('id') id: string, @CurrentUser() user: { id: string }) {
    const deleted = await this.brain.conversations.remove(id, user.id);
    if (!deleted) throw new NotFoundException('Conversation not found');
  }

  @Get(':id/messages')
  async listMessages(@Param('id') id: string, @CurrentUser() user: { id: string }) {
    // Verify ownership explicitly to return a clear 404 rather than an empty list.
    const conversation = await this.brain.conversations.findById(id, user.id);
    if (!conversation) throw new NotFoundException('Conversation not found');
    return this.brain.conversations.findMessages(id, user.id);
  }

  @Post(':id/messages')
  async addMessage(
    @Param('id') id: string,
    @Body() dto: SendMessageDto,
    @CurrentUser() user: { id: string },
  ) {
    const message = await this.brain.conversations.addMessage(
      {
        conversationId: id,
        role: dto.role,
        content: dto.content,
        metadata: dto.metadata,
      },
      user.id,
    );
    if (!message) throw new ForbiddenException('Conversation not found or access denied');
    return message;
  }
}
