import { Body, Controller, Post, Req, Res } from '@nestjs/common';
import type { Request, Response } from 'express';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import type { ModelMessage } from 'ai';
import { AssistantService } from './assistant.service';

interface ChatBody {
  messages: ModelMessage[];
  model?: string;
}

/**
 * AssistantController — "外部 agent" 模拟器聊天端点(SSE 流式)。
 *
 * POST /pac/v1/assistant/chat  —— 普通 JWT 鉴权(全局 guard);转发用户 token 给 MCP,
 * 工具在该用户 tenant scope 下执行。把 streamText 的 fullStream 部件转成 SSE 事件给前端:
 *   { type: 'text', text }            文本增量
 *   { type: 'tool_call', tool, args } 模型发起工具调用(前端可视化"调了哪个 PAC 工具")
 *   { type: 'tool_result', tool, result }
 *   { type: 'error', error } / { type: 'done' }
 */
@ApiTags('assistant')
@ApiBearerAuth('accessToken')
@Controller('assistant')
export class AssistantController {
  constructor(private readonly assistant: AssistantService) {}

  @Post('chat')
  @ApiOperation({ summary: '助手对话(SSE)— 模型自主调 PAC MCP 工具' })
  async chat(@Req() req: Request, @Res() res: Response, @Body() body: ChatBody): Promise<void> {
    const token = (req.headers['authorization'] ?? '').replace(/^Bearer\s+/i, '');

    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache, no-transform');
    res.setHeader('Connection', 'keep-alive');
    res.flushHeaders?.();

    const send = (event: Record<string, unknown>): void => {
      res.write(`data: ${JSON.stringify(event)}\n\n`);
    };

    const ac = new AbortController();
    req.on('close', () => ac.abort());

    try {
      const result = await this.assistant.chat({
        userToken: token,
        modelId: body.model,
        messages: body.messages ?? [],
        abortSignal: ac.signal,
      });

      for await (const part of result.fullStream) {
        const p = part as Record<string, unknown> & { type: string };
        switch (p.type) {
          case 'text-delta':
          case 'text':
            send({ type: 'text', text: (p.text as string) ?? (p.delta as string) ?? '' });
            break;
          case 'tool-call':
            send({ type: 'tool_call', tool: p.toolName, args: p.input });
            break;
          case 'tool-result':
            send({ type: 'tool_result', tool: p.toolName, result: p.output });
            break;
          case 'error':
            send({ type: 'error', error: String(p.error) });
            break;
          default:
            break;
        }
      }
      send({ type: 'done' });
    } catch (err) {
      send({ type: 'error', error: err instanceof Error ? err.message : String(err) });
    } finally {
      res.end();
    }
  }
}
