import {
  Controller,
  Get,
  Put,
  Delete,
  Param,
  Body,
  ClassSerializerInterceptor,
  UseInterceptors,
  Query,
  UseGuards,
  Logger,
  Req,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { UserService } from './users.service';
import { ApiOperation, ApiResponse, ApiQuery, ApiParam, ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import { UserResponseDto } from './dto/user-response.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { JwtAuthGuard } from 'common/guards/jwt-auth.guard';
import { RolesGuard } from 'common/guards/roles.guard';
import { UserRole, UserStatus } from 'common/enum/UserRole.enum';
import { Roles } from 'common/decorators/role.decorator';
import { UserFilterDto } from './dto/user-filter.dto';
import { Permissions } from 'common/decorators/permissions.decorator';
import { PermissionsGuard } from 'common/guards/ppermissions.guard';
import { PaginatedResponseDto } from 'common/utils/paginated-response.dto';

@ApiTags('Users')
@ApiBearerAuth()
@Controller({ path: 'users', version: '1' })
@UseInterceptors(ClassSerializerInterceptor)
@UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
export class UserController {
  private readonly logger = new Logger(UserController.name);
  constructor(private readonly userService: UserService) {}

  @Get()
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  // @Permissions('user:view')
  @ApiOperation({ summary: 'Get all users with pagination' })
  @ApiQuery({
    name: 'page',
    required: false,
    type: Number,
    description: 'Page number for pagination (default: 1)',
  })
  @ApiQuery({
    name: 'limit',
    required: false,
    type: Number,
    description: 'Number of items per page (default: 10)',
  })
  @ApiResponse({
    status: 200,
    description: 'List of users retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  async getAllUsers(@Query('page') page: number = 1, @Query('limit') limit: number = 10): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Fetching users - Page: ${page}, Limit: ${limit}`);
    return await this.userService.findAllUsers(page, limit);
  }

  @Get('filter')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get users by filter criteria' })
  @ApiQuery({ name: 'page', required: false, type: Number, default: 1 })
  @ApiQuery({ name: 'limit', required: false, type: Number, default: 10 })
  @ApiQuery({ name: 'role', required: false, type: String })
  @ApiQuery({ name: 'status', required: false, type: String })
  @ApiQuery({ name: 'searchTerm', required: false, type: String })
  @ApiQuery({ name: 'clientId', required: false, type: Number })
  @ApiResponse({
    status: 200,
    description: 'Filtered users retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  async getUsersByFilter(@Query() filter: UserFilterDto): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Filtering users with criteria: ${JSON.stringify(filter)}`);
    return await this.userService.findUsersByFilter(filter);
  }

  @Get('role/:role')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get users by role' })
  @ApiParam({ name: 'role', description: 'User role to filter by' })
  @ApiQuery({ name: 'page', required: false, type: Number, default: 1 })
  @ApiQuery({ name: 'limit', required: false, type: Number, default: 10 })
  @ApiResponse({
    status: 200,
    description: 'Users by role retrieved successfully',
    type: [UserResponseDto],
  })
  async getUsersByRole(
    @Param('role') role: UserRole,
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Fetching users with role: ${role}`);
    return await this.userService.findUserByRole(role, page, limit);
  }

  // Get users by client ID
  @Get('client/:clientId')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get users linked to a specific client' })
  @ApiParam({ name: 'clientId', description: 'Client ID to filter users by' })
  @ApiQuery({ name: 'page', required: false, type: Number, default: 1 })
  @ApiQuery({ name: 'limit', required: false, type: Number, default: 10 })
  @ApiResponse({
    status: 200,
    description: 'Users linked to client retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  async getUsersByClientId(
    @Param('clientId') clientId: string,
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Fetching users for client ID: ${clientId}`);
    return await this.userService.findUserByClientId(clientId, page, limit);
  }

  @Get('client/:clientId/linked')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get all users linked to a client (non-paginated)' })
  @ApiParam({ name: 'clientId', description: 'Client ID' })
  @ApiQuery({ name: 'page', required: false, type: Number, default: 1 })
  @ApiQuery({ name: 'limit', required: false, type: Number, default: 10 })
  @ApiResponse({
    status: 200,
    description: 'Linked users retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  async getLinkedUsersToClient(
    @Param('clientId') clientId: string,
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Fetching linked users for client ID: ${clientId}`);
    return await this.userService.getUsersLinkedToClient(clientId, page, limit);
  }

  @Get('status/:status')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get users by status' })
  @ApiParam({ name: 'status', description: 'User status to filter by' })
  @ApiQuery({ name: 'page', required: false, type: Number, default: 1 })
  @ApiQuery({ name: 'limit', required: false, type: Number, default: 10 })
  @ApiResponse({
    status: 200,
    description: 'Users by status retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  async getUsersByStatus(
    @Param('status') status: UserStatus,
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ): Promise<PaginatedResponseDto<UserResponseDto>> {
    this.logger.log(`Fetching users with status: ${status}`);
    return await this.userService.findUserByStatus(status, page, limit);
  }

  @Get('count/total')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get total user count' })
  @ApiResponse({
    status: 200,
    description: 'Total user count retrieved successfully',
    schema: { type: 'object', properties: { count: { type: 'number' } } },
  })
  async getTotalUserCount(): Promise<{ count: number }> {
    const count = await this.userService.countUsers();
    return { count };
  }

  @Get('count/role/:role')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get user count by role' })
  @ApiParam({ name: 'role', description: 'Role to count users for' })
  @ApiResponse({
    status: 200,
    description: 'User count by role retrieved successfully',
    schema: { type: 'object', properties: { role: { type: 'string' }, count: { type: 'number' } } },
  })
  async getUserCountByRole(@Param('role') role: UserRole): Promise<{ role: string; count: number }> {
    const count = await this.userService.getUserCountByRole(role);
    return { role, count };
  }

  @Get('email/:email')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.USER, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get user by email' })
  @ApiParam({ name: 'email', description: 'User email address' })
  @ApiResponse({
    status: 200,
    description: 'User found by email',
    type: UserResponseDto,
  })
  @ApiResponse({ status: 404, description: 'User not found' })
  async getUserByEmail(@Param('email') email: string): Promise<UserResponseDto> {
    this.logger.log(`Fetching user by email: ${email}`);
    return await this.userService.findUserByEmail(email);
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get user by ID' })
  @ApiParam({ name: 'id', description: 'User ID' })
  @ApiResponse({
    status: 200,
    description: 'User found',
    type: UserResponseDto,
  })
  @ApiResponse({ status: 404, description: 'User not found' })
  async getUserById(@Param('id') id: number): Promise<UserResponseDto> {
    this.logger.log(`Fetching user by ID: ${id}`);
    const user = await this.userService.findUserById(id);
    return user;
  }

  @Put(':id')
  @Roles(UserRole.ADMIN, UserRole.USER, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Update user' })
  @ApiParam({ name: 'id', description: 'User ID' })
  @ApiResponse({
    status: 200,
    description: 'User updated successfully',
    type: UserResponseDto,
  })
  @ApiResponse({ status: 404, description: 'User not found' })
  @ApiResponse({ status: 409, description: 'Email already exists' })
  async updateUser(@Param('id') id: number, @Body() updateUserDto: UpdateUserDto): Promise<UserResponseDto> {
    const user = await this.userService.updateUser(id, updateUserDto);
    return user;
  }

  @Delete(':id')
  @Roles(UserRole.SUPER_ADMIN)
  @Permissions('user:delete')
  @ApiOperation({ summary: 'Delete user' })
  @ApiParam({ name: 'id', description: 'User ID' })
  @ApiResponse({ status: 204, description: 'User deleted successfully' })
  @ApiResponse({ status: 404, description: 'User not found' })
  @HttpCode(HttpStatus.NO_CONTENT)
  async deleteUser(@Param('id') id: number): Promise<void> {
    this.logger.log(`Deleting user ID: ${id}`);
    await this.userService.deleteUser(id);
  }
}
