import { Controller, Get, Post, Patch, Delete, Body, Param, Res, Query, HttpCode, BadRequestException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import type { Response } from 'express';
import { RagChatService } from './rag-chat.service';
import type { CreateSessionResult } from './rag-chat.service';
import { QuotaGuardService } from '../membership/quota-guard.service';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import type { UserPayload } from '../../common/types';

@ApiTags('rag-chat')
@Controller('rag-chat')
@ApiBearerAuth()
export class RagChatController {
  constructor(
    private readonly svc: RagChatService,
    private readonly quotaGuard: QuotaGuardService,
  ) {}

  @Post('sessions')
  @ApiOperation({ summary: '创建/打开对话 (open-or-create)' })
  async createSession(
    @CurrentUser() user: UserPayload,
    @Res({ passthrough: true }) res: Response,
    @Body() dto: {
      scopeType: string;
      scopeId?: string | null;
      parentKnowledgeBaseId?: string | null;
      createdFrom?: string;
      title?: string;
    },
  ) {
    const result: CreateSessionResult = await this.svc.createSession(String(user.id), {
      scopeType: dto.scopeType,
      scopeId: dto.scopeId ?? null,
      parentKnowledgeBaseId: dto.parentKnowledgeBaseId ?? null,
      createdFrom: dto.createdFrom,
      title: dto.title,
    });

    res.status(result.isNew ? 201 : 200);
    return result.session;
  }

  @Get('sessions')
  @ApiOperation({ summary: '对话列表' })
  async listSessions(
    @CurrentUser() user: UserPayload,
    @Query('scopeType') scopeType?: string,
    @Query('scopeId') scopeId?: string,
    @Query('parentKnowledgeBaseId') parentKnowledgeBaseId?: string,
    @Query('knowledgeBaseId') kbId?: string,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
  ) {
    return this.svc.listSessions(String(user.id), {
      scopeType,
      scopeId,
      parentKnowledgeBaseId,
      kbId,
      page: page ? parseInt(page, 10) : undefined,
      limit: limit ? parseInt(limit, 10) : undefined,
    });
  }

  @Get('sessions/:id/messages')
  @ApiOperation({ summary: '对话历史' })
  async messages(@CurrentUser() user: UserPayload, @Param('id') id: string) {
    return this.svc.getMessages(String(user.id), id);
  }

  @Post('sessions/:id/messages')
  @ApiOperation({ summary: '发送消息（同步）' })
  async sendMessage(@CurrentUser() user: UserPayload, @Param('id') id: string, @Body() dto: { content: string }) {
    const userId = String(user.id);
    const opId = `chat:${id}:${Date.now()}`;
    const check = await this.quotaGuard.check(userId, 'ai_chat_messages', opId);
    if (!check.allowed) throw new BadRequestException(this.quotaGuard.buildError(check));
    try {
      const result = await this.svc.sendMessage(userId, id, dto.content);
      this.quotaGuard.confirm(opId).catch(() => {});
      return result;
    } catch {
      this.quotaGuard.cancel(opId).catch(() => {});
      throw new BadRequestException('AI Chat failed');
    }
  }

  @Post('sessions/:id/stream')
  @ApiOperation({ summary: '发送消息（SSE 流式，支持思考过程）' })
  async sendMessageStream(@CurrentUser() user: UserPayload, @Param('id') id: string, @Body() dto: { content: string }, @Res() res: Response) {
    const userId = String(user.id);
    const opId = `chat_stream:${id}:${Date.now()}`;
    const check = await this.quotaGuard.check(userId, 'ai_chat_messages', opId);
    if (!check.allowed) {
      res.status(429).json(this.quotaGuard.buildError(check));
      return;
    }
    res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('X-Accel-Buffering', 'no');

    try {
      for await (const chunk of this.svc.sendMessageStream(userId, id, dto.content)) {
        if (res.destroyed) { this.quotaGuard.cancel(opId).catch(() => {}); break; }
        res.write(`data: ${JSON.stringify(chunk)}\n\n`);
      }
      if (!res.destroyed) { res.end(); this.quotaGuard.confirm(opId).catch(() => {}); }
    } catch {
      if (!res.destroyed) res.end();
      this.quotaGuard.cancel(opId).catch(() => {});
    }
  }

  @Patch('sessions/:id')
  @ApiOperation({ summary: '更新会话属性' })
  async updateSession(
    @CurrentUser() user: UserPayload,
    @Param('id') id: string,
    @Body() dto: {
      title?: string;
      isPinned?: boolean;
      isArchived?: boolean;
      modelMode?: string;
      modelId?: string | null;
    },
  ) {
    return this.svc.updateSession(String(user.id), id, dto);
  }

  @Delete('sessions/:id')
  @ApiOperation({ summary: '删除对话（软删除）' })
  async deleteSession(@CurrentUser() user: UserPayload, @Param('id') id: string) {
    return this.svc.deleteSession(String(user.id), id);
  }
}
