import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFile,
  Body,
  Req,
  BadRequestException,
  Logger,
  UseGuards,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { VoiceService } from './voice.service';
import { Public } from '../auth/decorators/public.decorator';
import { SaveVoiceFeedbackDto } from './dto/save-voice-feedback.dto';

@Controller('api/v1/voice')
export class VoiceController {
  private readonly logger = new Logger('VoiceController');

  constructor(private readonly voiceService: VoiceService) {}

  @Post('transcribe')
  @UseInterceptors(FileInterceptor('audio'))
  async transcribeAudio(
    @UploadedFile() file: Express.Multer.File,
    @Body('text') text?: string,
    @Body('language') language?: string,
    @Body('childName') childName?: string,
    @Body('availableChildren') availableChildrenJson?: string,
  ) {
    this.logger.log('=== Voice Transcribe Request ===');
    this.logger.log(
      `Mode: ${text ? 'Text Classification (Web Speech API)' : 'Audio Transcription (MediaRecorder)'}`,
    );
    this.logger.log(`Language: ${language || 'en'}`);
    this.logger.log(`Child Name: ${childName || 'none'}`);

    // Parse available children if provided
    let availableChildren: Array<{ id: string; name: string }> | undefined;
    if (availableChildrenJson) {
      try {
        availableChildren = JSON.parse(availableChildrenJson);
        this.logger.log(`Available Children: ${availableChildren?.map(c => c.name).join(', ')}`);
      } catch (error) {
        this.logger.warn(`Failed to parse availableChildren: ${error.message}`);
      }
    }

    // If text is provided (from Web Speech API), classify it directly
    if (text) {
      this.logger.log(`Input Text: "${text}"`);

      const result = await this.voiceService.extractActivityFromText(
        text,
        language || 'en',
        childName,
        availableChildren,
      );

      this.logger.log(
        `Classification Result: ${JSON.stringify(result, null, 2)}`,
      );
      this.logger.log('=== Request Complete ===\n');

      return {
        success: true,
        transcript: text,
        classification: result,
      };
    }

    // Otherwise, transcribe the audio file
    if (!file) {
      this.logger.error('No audio file or text provided');
      throw new BadRequestException('Audio file or text is required');
    }

    this.logger.log(
      `Audio File: ${file.originalname} (${file.size} bytes, ${file.mimetype})`,
    );

    const transcription = await this.voiceService.transcribeAudio(
      file.buffer,
      language,
    );

    this.logger.log(
      `Transcription: "${transcription.text}" (${transcription.language})`,
    );

    // Also classify the transcription with multi-child support
    const classification = await this.voiceService.extractActivityFromText(
      transcription.text,
      language || 'en',
      childName,
      availableChildren,
    );

    this.logger.log(
      `Classification Result: ${JSON.stringify(classification, null, 2)}`,
    );
    this.logger.log('=== Request Complete ===\n');

    return {
      success: true,
      transcript: transcription.text,
      classification: classification,
    };
  }

  @Post('process')
  @UseInterceptors(FileInterceptor('audio'))
  async processVoiceInput(
    @UploadedFile() file: Express.Multer.File,
    @Body('language') language?: string,
    @Body('childName') childName?: string,
    @Body('availableChildren') availableChildrenJson?: string,
  ) {
    if (!file) {
      throw new BadRequestException('Audio file is required');
    }

    // Parse available children if provided
    let availableChildren: Array<{ id: string; name: string }> | undefined;
    if (availableChildrenJson) {
      try {
        availableChildren = JSON.parse(availableChildrenJson);
      } catch (error) {
        this.logger.warn(`Failed to parse availableChildren: ${error.message}`);
      }
    }

    const result = await this.voiceService.processVoiceInput(
      file.buffer,
      language,
      childName,
      availableChildren,
    );

    return {
      success: true,
      data: result,
    };
  }

  @Post('extract-activity')
  async extractActivity(
    @Body('text') text: string,
    @Body('language') language: string,
    @Body('childName') childName?: string,
    @Body('availableChildren') availableChildren?: Array<{ id: string; name: string }>,
  ) {
    if (!text) {
      throw new BadRequestException('Text is required');
    }

    const result = await this.voiceService.extractActivityFromText(
      text,
      language || 'en',
      childName,
      availableChildren,
    );

    return {
      success: true,
      data: result,
    };
  }

  @Post('clarify')
  async getClarification(
    @Body('text') text: string,
    @Body('activityType') activityType: string,
    @Body('language') language: string,
  ) {
    if (!text || !activityType) {
      throw new BadRequestException('Text and activity type are required');
    }

    const question = await this.voiceService.generateClarificationQuestion(
      text,
      activityType,
      language || 'en',
    );

    return {
      success: true,
      data: {
        question,
      },
    };
  }

  /**
   * Test endpoint for voice classification (public, for development/testing only)
   * IMPORTANT: Remove @Public() decorator in production
   */
  @Public()
  @Post('test-classify')
  async testClassify(
    @Body('text') text: string,
    @Body('language') language?: string,
    @Body('childName') childName?: string,
  ) {
    if (!text) {
      throw new BadRequestException('Text is required');
    }

    this.logger.log(`[TEST] Voice classification request: "${text}"`);

    const result = await this.voiceService.extractActivityFromText(
      text,
      language || 'en',
      childName,
    );

    this.logger.log(
      `[TEST] Classification result: ${JSON.stringify(result, null, 2)}`,
    );

    return {
      success: true,
      transcript: text,
      classification: result,
    };
  }

  @Post('feedback')
  @UseGuards(JwtAuthGuard)
  async saveFeedback(
    @Req() req: any,
    @Body() feedbackDto: SaveVoiceFeedbackDto,
  ) {
    const userId = req.user.userId;

    this.logger.log(
      `[Voice Feedback] User ${userId} submitting feedback: ${feedbackDto.action}`,
    );

    const feedback = await this.voiceService.saveFeedback(userId, feedbackDto);

    return {
      success: true,
      data: feedback,
    };
  }
}
