import {
  Controller,
  Get,
  Post,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Logger,
  Res,
} from '@nestjs/common';
import { Response } from 'express';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { Public } from '../auth/decorators/public.decorator';
import { MessagesService, SendMessageDto } from './messages.service';

// DTO for incoming Signal webhook
interface SignalWebhookPayload {
  envelope: {
    source: string;
    sourceNumber?: string;
    sourceName?: string;
    timestamp: number;
    dataMessage?: {
      timestamp: number;
      message: string;
    };
  };
  account: string;
}

@Controller('signal/messages')
export class MessagesController {
  private readonly logger = new Logger(MessagesController.name);

  constructor(private readonly messagesService: MessagesService) {}

  /**
   * Get messages for a specific driver
   */
  @Get('driver/:driverId')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async getMessagesForDriver(
    @Param('driverId') driverId: string,
    @Query('limit') limit?: string,
  ) {
    const messages = await this.messagesService.getMessagesForDriver(
      driverId,
      limit ? parseInt(limit, 10) : 50,
    );
    // Return in chronological order for display
    return messages.reverse();
  }

  /**
   * Send a message to a driver
   */
  @Post('send')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async sendMessage(@Body() dto: SendMessageDto) {
    return this.messagesService.sendMessage(dto);
  }

  /**
   * Mark messages as read for a driver
   */
  @Post('driver/:driverId/read')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async markAsRead(@Param('driverId') driverId: string) {
    const result = await this.messagesService.markMessagesAsRead(driverId);
    return { success: true, count: result.count };
  }

  /**
   * Get unread message counts for all drivers
   */
  @Get('unread')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async getUnreadCounts() {
    return this.messagesService.getUnreadCounts();
  }

  /**
   * Get unread count for a specific driver
   */
  @Get('driver/:driverId/unread')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async getUnreadCountForDriver(@Param('driverId') driverId: string) {
    const count = await this.messagesService.getUnreadCountForDriver(driverId);
    return { driverId, unread: count };
  }

  /**
   * Webhook endpoint for incoming Signal messages
   * This is called by signal-cli-rest-api when messages are received
   * Public endpoint - no authentication required
   */
  @Public()
  @Post('webhook')
  async handleWebhook(@Body() payload: SignalWebhookPayload) {
    this.logger.debug('Received Signal webhook:', JSON.stringify(payload));

    try {
      const envelope = payload.envelope;

      if (!envelope?.dataMessage?.message) {
        this.logger.debug('Webhook received but no message content');
        return { success: true, message: 'No message content' };
      }

      const fromNumber = envelope.sourceNumber || envelope.source;
      const content = envelope.dataMessage.message;
      const timestamp = envelope.dataMessage.timestamp?.toString();

      const message = await this.messagesService.processIncomingMessage(
        fromNumber,
        content,
        timestamp,
      );

      if (message) {
        return { success: true, messageId: message.id };
      } else {
        return { success: true, message: 'Unknown sender' };
      }
    } catch (error: any) {
      this.logger.error('Failed to process webhook:', error.message);
      return { success: false, error: error.message };
    }
  }

  /**
   * Export all messages as a text file
   */
  @Get('export')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR')
  async exportMessages(@Res() res: Response) {
    const exportData = await this.messagesService.exportAllMessages();

    const filename = `signal-chats-${new Date().toISOString().split('T')[0]}.txt`;

    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
    res.send(exportData);
  }

  /**
   * Delete all messages
   */
  @Delete('all')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR')
  async deleteAllMessages() {
    const count = await this.messagesService.deleteAllMessages();
    return { success: true, deleted: count };
  }

  /**
   * Get message statistics
   */
  @Get('stats')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async getMessageStats() {
    return this.messagesService.getMessageStats();
  }

  /**
   * Check which events have driver responses since the event started
   * Used to determine if the "awaiting response" glow should show
   */
  @Post('check-responses')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMINISTRATOR', 'COORDINATOR')
  async checkDriverResponses(
    @Body()
    body: {
      events: Array<{ eventId: string; driverId: string; startTime: string }>;
    },
  ) {
    const pairs = body.events.map((e) => ({
      eventId: e.eventId,
      driverId: e.driverId,
      sinceTime: new Date(e.startTime),
    }));

    const respondedEventIds =
      await this.messagesService.checkDriverResponsesSince(pairs);
    return { respondedEventIds };
  }
}
