import {
  Body,
  Controller,
  Post,
  Request,
  Res,
  UseGuards,
} from '@nestjs/common';
import { Response } from 'express';
import { ChatMessage, ChatService } from './chat.service';
import { CombinedAuthGuard } from '../auth/combined-auth.guard';
import { ModelConfigService } from '../model-config/model-config.service';
import { TenantService } from '../tenant/tenant.service';
import { ModelType } from '../types';

class StreamChatDto {
  message: string;
  history: ChatMessage[];
  userLanguage?: string;
  selectedEmbeddingId?: string;
  selectedLLMId?: string;
  selectedGroups?: string[];
  selectedFiles?: string[];
  historyId?: string;
  enableRerank?: boolean;
  selectedRerankId?: string;
  temperature?: number;
  maxTokens?: number;
  topK?: number;
  similarityThreshold?: number;
  rerankSimilarityThreshold?: number;
  enableQueryExpansion?: boolean;
  enableHyDE?: boolean;
}

@Controller('chat')
@UseGuards(CombinedAuthGuard)
export class ChatController {
  constructor(
    private chatService: ChatService,
    private modelConfigService: ModelConfigService,
    private tenantService: TenantService,
  ) { }

  @Post('stream')
  async streamChat(
    @Request() req,
    @Body() body: StreamChatDto,
    @Res() res: Response,
  ) {
    try {
      console.log('Full Request Body:', JSON.stringify(body, null, 2));
      const { message, history = [], userLanguage = 'zh', selectedEmbeddingId, selectedLLMId, selectedGroups, selectedFiles, historyId, enableRerank, selectedRerankId, temperature, maxTokens, topK, similarityThreshold, rerankSimilarityThreshold, enableQueryExpansion, enableHyDE } = body;
      const userId = req.user.id;

      console.log('=== Chat Debug Info ===');
      console.log('User ID:', userId);
      console.log('Message:', message);
      console.log('User Language:', userLanguage);
      console.log('Selected Embedding ID:', selectedEmbeddingId);
      console.log('Selected LLM ID:', selectedLLMId);
      console.log('Selected Groups:', selectedGroups);
      console.log('Selected Files:', selectedFiles);
      console.log('History ID:', historyId);
      console.log('Temperature:', temperature);
      console.log('Max Tokens:', maxTokens);
      console.log('Top K:', topK);
      console.log('Similarity Threshold:', similarityThreshold);
      console.log('Rerank Similarity Threshold:', rerankSimilarityThreshold);
      console.log('Query Expansion:', enableQueryExpansion);
      console.log('HyDE:', enableHyDE);

      const role = req.user.role;
      const tenantId = req.user.tenantId;


      let models = await this.modelConfigService.findAll(userId, tenantId);

      if (role !== 'SUPER_ADMIN') {
        const tenantSettings = await this.tenantService.getSettings(tenantId);
        const enabledIds = tenantSettings.enabledModelIds || [];
        // Only allow models that are enabled by the tenant admin
        models = models.filter(m => enabledIds.includes(m.id));
      }

      let llmModel;
      if (selectedLLMId) {
        // Find specifically selected model
        llmModel = await this.modelConfigService.findOne(selectedLLMId, userId, tenantId);
        console.log('Using selected LLM model:', llmModel.name);
      } else {
        // Use organization's default LLM from Index Chat Config (strict)
        llmModel = await this.modelConfigService.findDefaultByType(tenantId, ModelType.LLM);
        console.log('Final LLM model used (default):', llmModel ? llmModel.name : 'None');
      }


      res.setHeader('Content-Type', 'text/event-stream');
      res.setHeader('Cache-Control', 'no-cache');
      res.setHeader('Connection', 'keep-alive');
      res.setHeader('Access-Control-Allow-Origin', '*');

      if (!llmModel) {
        res.write(
          `data: ${JSON.stringify({ type: 'error', data: 'Please add LLM model and configure API key in model management' })}\n\n`,
        );
        res.write('data: [DONE]\n\n');
        res.end();
        return;
      }

      const stream = this.chatService.streamChat(
        message,
        history,
        userId,
        llmModel as any,
        userLanguage,
        selectedEmbeddingId,
        selectedGroups,
        selectedFiles,
        historyId,
        enableRerank,
        selectedRerankId,
        temperature,
        maxTokens,
        topK,
        similarityThreshold,
        rerankSimilarityThreshold,
        enableQueryExpansion,
        enableHyDE,
        req.user.tenantId // Pass tenant ID
      );

      for await (const chunk of stream) {
        res.write(`data: ${JSON.stringify(chunk)}\n\n`);
      }

      res.write('data: [DONE]\n\n');
      res.end();
    } catch (error) {
      console.error('Stream chat error:', error);
      try {
        res.write(
          `data: ${JSON.stringify({ type: 'error', data: error.message || 'Server Error' })}\n\n`,
        );
        res.write('data: [DONE]\n\n');
        res.end();
      } catch (writeError) {
        console.error('Failed to write error response:', writeError);
      }
    }
  }

  @Post('assist')
  async streamAssist(
    @Request() req,
    @Body() body: { instruction: string; context: string },
    @Res() res: Response,
  ) {
    try {
      const { instruction, context } = body;
      const userId = req.user.id; // Corrected to use req.user.id
      const tenantId = req.user.tenantId;
      const role = req.user.role;

      // Use organization's default LLM from Index Chat Config (strict)
      const llmModel = await this.modelConfigService.findDefaultByType(tenantId, ModelType.LLM);

      res.setHeader('Content-Type', 'text/event-stream');
      res.setHeader('Cache-Control', 'no-cache');
      res.setHeader('Connection', 'keep-alive');
      res.setHeader('Access-Control-Allow-Origin', '*');

      if (!llmModel) {
        res.write(
          `data: ${JSON.stringify({ type: 'error', data: 'LLM model configuration not found' })}\n\n`,
        );
        res.write('data: [DONE]\n\n');
        res.end();
        return;
      }

      const stream = this.chatService.streamAssist(
        instruction,
        context,
        llmModel as any,
      );

      for await (const chunk of stream) {
        res.write(`data: ${JSON.stringify(chunk)}\n\n`);
      }

      res.write('data: [DONE]\n\n');
      res.end();
    } catch (error) {
      console.error('Stream assist error:', error);
      res.write(
        `data: ${JSON.stringify({ type: 'error', data: error.message || 'Server Error' })}\n\n`,
      );
      res.write('data: [DONE]\n\n');
      res.end();
    }
  }
}
