import {
  Controller,
  Get,
  Put,
  Patch,
  Body,
  Param,
  Query,
  UseGuards,
  Inject,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery, ApiProperty  } from '@nestjs/swagger';
import { NotificationChannel as PrismaChannel } from '@prisma/client';
import { IsBoolean, IsEnum, IsString } from 'class-validator';
import { CurrentUser, type JwtPayload } from '@modules/auth';
import {
  NOTIFICATION_REPOSITORY,
  type INotificationRepository,
  NOTIFICATION_PREFERENCE_REPOSITORY,
  type INotificationPreferenceRepository,
} from '../../domain';
import { TemplateService } from '../../infrastructure/services/template.service';
import { NotificationsGateway } from '../gateways/notifications.gateway';

class UpdatePreferenceDto {
  @ApiProperty({ enum: PrismaChannel, description: 'Notification channel' })
  @IsEnum(PrismaChannel)
  channel!: PrismaChannel;

  @ApiProperty({ description: 'Event type identifier' })
  @IsString()
  eventType!: string;

  @ApiProperty({ description: 'Whether the preference is enabled' })
  @IsBoolean()
  enabled!: boolean;
}

@ApiTags('notifications')
@ApiBearerAuth('JWT')
@Controller('notifications')
@UseGuards(AuthGuard('jwt'))
export class NotificationsController {
  constructor(
    @Inject(NOTIFICATION_REPOSITORY)
    private readonly notificationRepo: INotificationRepository,
    @Inject(NOTIFICATION_PREFERENCE_REPOSITORY)
    private readonly preferenceRepo: INotificationPreferenceRepository,
    private readonly templateService: TemplateService,
    private readonly notificationsGateway: NotificationsGateway,
  ) {}

  @Get('history')
  @ApiOperation({ summary: 'Get notification history' })
  @ApiResponse({ status: 200, description: 'Notification history retrieved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  async getHistory(
    @CurrentUser() user: JwtPayload,
    @Query('limit') limit?: number,
  ) {
    return this.notificationRepo.findByUserId(user.sub, limit ?? 50);
  }

  @Get('preferences')
  @ApiOperation({ summary: 'Get notification preferences' })
  @ApiResponse({ status: 200, description: 'Preferences retrieved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async getPreferences(@CurrentUser() user: JwtPayload) {
    return this.preferenceRepo.findByUserId(user.sub);
  }

  @Put('preferences')
  @ApiOperation({ summary: 'Update a notification preference' })
  @ApiResponse({ status: 200, description: 'Preference updated' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async updatePreference(
    @CurrentUser() user: JwtPayload,
    @Body() dto: UpdatePreferenceDto,
  ) {
    return this.preferenceRepo.upsert(user.sub, dto.channel, dto.eventType, dto.enabled);
  }

  @Get('unread-count')
  @ApiOperation({ summary: 'Get unread notification count (Redis-cached)' })
  @ApiResponse({ status: 200, description: 'Unread count retrieved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async getUnreadCount(@CurrentUser() user: JwtPayload) {
    const count = await this.notificationsGateway.getUnreadCount(user.sub);
    return { unreadCount: count };
  }

  @Get('unread')
  @ApiOperation({ summary: 'Get unread notifications' })
  @ApiResponse({ status: 200, description: 'Unread notifications retrieved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  async getUnread(
    @CurrentUser() user: JwtPayload,
    @Query('limit') limit?: number,
  ) {
    const [notifications, count] = await Promise.all([
      this.notificationRepo.findUnreadByUserId(user.sub, limit ?? 50),
      this.notificationRepo.countUnreadByUserId(user.sub),
    ]);
    return { notifications, unreadCount: count };
  }

  @Patch(':id/read')
  @ApiOperation({ summary: 'Mark a notification as read' })
  @ApiResponse({ status: 200, description: 'Notification marked as read' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async markAsRead(
    @CurrentUser() user: JwtPayload,
    @Param('id') id: string,
  ) {
    await this.notificationRepo.markAsRead(id, user.sub);
    // Invalidate cached count and push updated count via WebSocket
    await this.notificationsGateway.invalidateUnreadCount(user.sub);
    await this.notificationsGateway.emitUnreadCount(user.sub);
    return { success: true };
  }

  @Patch('read-all')
  @ApiOperation({ summary: 'Mark all notifications as read' })
  @ApiResponse({ status: 200, description: 'All notifications marked as read' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async markAllAsRead(@CurrentUser() user: JwtPayload) {
    const count = await this.notificationRepo.markAllAsRead(user.sub);
    // Invalidate cached count and push updated count via WebSocket
    await this.notificationsGateway.invalidateUnreadCount(user.sub);
    await this.notificationsGateway.emitUnreadCount(user.sub);
    return { markedCount: count };
  }

  @Get('templates')
  @ApiOperation({ summary: 'Get available notification templates' })
  @ApiResponse({ status: 200, description: 'Templates retrieved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async getTemplates() {
    return { templates: this.templateService.getTemplateKeys() };
  }
}
