/**
 * Notifications Controller
 *
 * REST API endpoints for managing notifications
 */

import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Param,
  Query,
  UseGuards,
  ParseIntPipe,
  DefaultValuePipe,
  NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger';
import { NotificationService } from '../services/notification.service';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { CurrentUser, UserPayload } from '../decorators/current-user.decorator';
import { Notification } from '@domain/entities/notification.entity';

class NotificationResponseDto {
  id: string;
  type: string;
  priority: string;
  title: string;
  message: string;
  metadata?: Record<string, any>;
  read: boolean;
  readAt?: string;
  actionUrl?: string;
  createdAt: string;
}

@ApiTags('Notifications')
@ApiBearerAuth()
@Controller('notifications')
@UseGuards(JwtAuthGuard)
export class NotificationsController {
  constructor(private readonly notificationService: NotificationService) {}

  /**
   * Get user's notifications
   */
  @Get()
  @ApiOperation({ summary: 'Get user notifications' })
  @ApiResponse({ status: 200, description: 'Notifications retrieved successfully' })
  @ApiQuery({ name: 'read', required: false, description: 'Filter by read status' })
  @ApiQuery({ name: 'page', required: false, description: 'Page number (default: 1)' })
  @ApiQuery({ name: 'limit', required: false, description: 'Items per page (default: 20)' })
  async getNotifications(
    @CurrentUser() user: UserPayload,
    @Query('read') read?: string,
    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page?: number,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit?: number
  ): Promise<{
    notifications: NotificationResponseDto[];
    total: number;
    page: number;
    pageSize: number;
  }> {
    page = page || 1;
    limit = limit || 20;

    const filters: any = {
      userId: user.id,
      read: read !== undefined ? read === 'true' : undefined,
      offset: (page - 1) * limit,
      limit,
    };

    const { notifications, total } = await this.notificationService.getNotifications(filters);

    return {
      notifications: notifications.map(n => this.mapToDto(n)),
      total,
      page,
      pageSize: limit,
    };
  }

  /**
   * Get unread notifications
   */
  @Get('unread')
  @ApiOperation({ summary: 'Get unread notifications' })
  @ApiResponse({ status: 200, description: 'Unread notifications retrieved successfully' })
  @ApiQuery({
    name: 'limit',
    required: false,
    description: 'Number of notifications (default: 50)',
  })
  async getUnreadNotifications(
    @CurrentUser() user: UserPayload,
    @Query('limit', new DefaultValuePipe(50), ParseIntPipe) limit?: number
  ): Promise<NotificationResponseDto[]> {
    limit = limit || 50;
    const notifications = await this.notificationService.getUnreadNotifications(user.id, limit);
    return notifications.map(n => this.mapToDto(n));
  }

  /**
   * Get unread count
   */
  @Get('unread/count')
  @ApiOperation({ summary: 'Get unread notifications count' })
  @ApiResponse({ status: 200, description: 'Unread count retrieved successfully' })
  async getUnreadCount(@CurrentUser() user: UserPayload): Promise<{ count: number }> {
    const count = await this.notificationService.getUnreadCount(user.id);
    return { count };
  }

  /**
   * Get notification by ID
   */
  @Get(':id')
  @ApiOperation({ summary: 'Get notification by ID' })
  @ApiResponse({ status: 200, description: 'Notification retrieved successfully' })
  @ApiResponse({ status: 404, description: 'Notification not found' })
  async getNotificationById(
    @CurrentUser() user: UserPayload,
    @Param('id') id: string
  ): Promise<NotificationResponseDto> {
    const notification = await this.notificationService.getNotificationById(id);

    if (!notification || notification.userId !== user.id) {
      throw new NotFoundException('Notification not found');
    }

    return this.mapToDto(notification);
  }

  /**
   * Mark notification as read
   */
  @Patch(':id/read')
  @ApiOperation({ summary: 'Mark notification as read' })
  @ApiResponse({ status: 200, description: 'Notification marked as read' })
  @ApiResponse({ status: 404, description: 'Notification not found' })
  async markAsRead(
    @CurrentUser() user: UserPayload,
    @Param('id') id: string
  ): Promise<{ success: boolean }> {
    const notification = await this.notificationService.getNotificationById(id);

    if (!notification || notification.userId !== user.id) {
      throw new NotFoundException('Notification not found');
    }

    await this.notificationService.markAsRead(id);
    return { success: true };
  }

  /**
   * Mark all notifications as read
   */
  @Post('read-all')
  @ApiOperation({ summary: 'Mark all notifications as read' })
  @ApiResponse({ status: 200, description: 'All notifications marked as read' })
  async markAllAsRead(@CurrentUser() user: UserPayload): Promise<{ success: boolean }> {
    await this.notificationService.markAllAsRead(user.id);
    return { success: true };
  }

  /**
   * Delete notification
   */
  @Delete(':id')
  @ApiOperation({ summary: 'Delete notification' })
  @ApiResponse({ status: 200, description: 'Notification deleted' })
  @ApiResponse({ status: 404, description: 'Notification not found' })
  async deleteNotification(
    @CurrentUser() user: UserPayload,
    @Param('id') id: string
  ): Promise<{ success: boolean }> {
    const notification = await this.notificationService.getNotificationById(id);

    if (!notification || notification.userId !== user.id) {
      throw new NotFoundException('Notification not found');
    }

    await this.notificationService.deleteNotification(id);
    return { success: true };
  }

  /**
   * Map notification entity to DTO
   */
  private mapToDto(notification: Notification): NotificationResponseDto {
    return {
      id: notification.id,
      type: notification.type,
      priority: notification.priority,
      title: notification.title,
      message: notification.message,
      metadata: notification.metadata,
      read: notification.read,
      readAt: notification.readAt?.toISOString(),
      actionUrl: notification.actionUrl,
      createdAt: notification.createdAt.toISOString(),
    };
  }
}
