import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Query,
  Req,
  UnauthorizedException,
  UseGuards,
} from '@nestjs/common';
import type { Request } from 'express';

import { Roles } from '@/casl/roles.decorator';
import { RolesGuard } from '@/casl/roles.guard';
import { JwtAuthGuard } from '@/modules/auth/jwt-auth.guard';

import { CreateSystemNotificationDto } from './dto/create-system-notification.dto';
import { GetSystemNotificationsQueryDto } from './dto/get-system-notifications-query.dto';
import { SystemNotificationsService } from './system-notifications.service';

const NOTIFICATION_READ_ROLES = [
  'admin',
  'ministry',
  'private_sector',
  'cdc_g-psf',
  'cdc',
  'cefp',
];

type AuthenticatedRequest = Request & {
  user?: {
    id?: number;
  };
};

@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(...NOTIFICATION_READ_ROLES)
@Controller('system-notifications')
export class SystemNotificationsController {
  constructor(
    private readonly systemNotificationsService: SystemNotificationsService,
  ) {}

  @Post()
  @Roles('admin')
  create(@Body() dto: CreateSystemNotificationDto) {
    return this.systemNotificationsService.create(dto);
  }

  @Get()
  findAll(
    @Req() request: AuthenticatedRequest,
    @Query() query: GetSystemNotificationsQueryDto,
  ) {
    return this.systemNotificationsService.findAllForCurrentUser(
      this.getCurrentUserId(request),
      query,
    );
  }

  @Get('unread-count')
  unreadCount(@Req() request: AuthenticatedRequest) {
    return this.systemNotificationsService.unreadCountForCurrentUser(
      this.getCurrentUserId(request),
    );
  }

  @Get(':id')
  findOne(
    @Req() request: AuthenticatedRequest,
    @Param('id', ParseIntPipe) id: number,
  ) {
    return this.systemNotificationsService.findOneForCurrentUser(
      id,
      this.getCurrentUserId(request),
    );
  }

  @Patch('read-all')
  markAllAsRead(@Req() request: AuthenticatedRequest) {
    return this.systemNotificationsService.markAllAsReadForCurrentUser(
      this.getCurrentUserId(request),
    );
  }

  @Patch(':id/read')
  markAsRead(
    @Req() request: AuthenticatedRequest,
    @Param('id', ParseIntPipe) id: number,
  ) {
    return this.systemNotificationsService.markAsReadForCurrentUser(
      id,
      this.getCurrentUserId(request),
    );
  }

  @Delete(':id')
  softDelete(
    @Req() request: AuthenticatedRequest,
    @Param('id', ParseIntPipe) id: number,
  ) {
    return this.systemNotificationsService.softDeleteForCurrentUser(
      id,
      this.getCurrentUserId(request),
    );
  }

  private getCurrentUserId(request: AuthenticatedRequest): number {
    const userId = Number(request.user?.id);

    if (!Number.isInteger(userId) || userId <= 0) {
      throw new UnauthorizedException('Invalid authenticated user.');
    }

    return userId;
  }
}
