import { Controller, Get, Post, Put, Delete, Body, Param, Query, ParseIntPipe, HttpStatus, HttpCode, UseGuards, Logger } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery, ApiBody } from '@nestjs/swagger';
import { ClientService } from './client.service';
import { ClientResponseDto } from './dto/client-response.dto';
import { CreateClientDto } from './dto/create-client.dto';
import { UpdateClientDto } from './dto/update-client.dto';
import { PaginatedClientDto } from './dto/paginated-client.dto';
import { PlanResponseDto } from './dto/plan.dto';
import { PlanDataDto } from './dto/plan-data.dto';
import { PaginatedResponseDto } from 'common/utils/paginated-response.dto';
import { UserResponseDto } from 'modules/user/dto/user-response.dto';
import { JwtAuthGuard } from 'common/guards/jwt-auth.guard';
import { RolesGuard } from 'common/guards/roles.guard';
import { Roles } from 'common/decorators/role.decorator';
import { UserRole } from 'common/enum/UserRole.enum';

@ApiTags('Client')
@Controller({ path: 'client', version: '1' })
// @UseGuards(JwtAuthGuard, RolesGuard)
export class ClientController {
  private readonly logger = new Logger(ClientController.name);
  constructor(private readonly clientService: ClientService) {}

  @Post()
  @Roles(UserRole.SUPER_ADMIN)
  @ApiOperation({ summary: 'Create a new client' })
  @ApiResponse({
    status: 201,
    description: 'Client created successfully',
    type: ClientResponseDto,
  })
  @ApiResponse({
    status: 409,
    description: 'Client with this email already exists',
  })
  @ApiBody({ type: CreateClientDto })
  async createClient(@Body() createClientDto: CreateClientDto): Promise<ClientResponseDto> {
    return this.clientService.createClient(createClientDto);
  }

  @Get()
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Get all clients with pagination' })
  @ApiResponse({
    status: 200,
    description: 'Clients retrieved successfully',
    type: PaginatedClientDto,
  })
  @ApiQuery({
    name: 'page',
    required: false,
    type: Number,
    description: 'Page number (default: 1)',
  })
  @ApiQuery({
    name: 'limit',
    required: false,
    type: Number,
    description: 'Items per page (default: 10)',
  })
  async getAllClients(@Query('page') page: number = 1, @Query('limit') limit: number = 10): Promise<PaginatedClientDto> {
    return this.clientService.getAllClients(page, limit);
  }

  @Get(':id')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get client by ID' })
  @ApiResponse({
    status: 200,
    description: 'Client retrieved successfully',
    type: ClientResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  async getClientById(@Param('id') id: string): Promise<ClientResponseDto> {
    return this.clientService.getClientById(id);
  }

  @Get(':id/plan')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get client plan information' })
  @ApiResponse({
    status: 200,
    description: 'Client plan retrieved successfully',
    type: PlanResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  async getClientPlan(@Param('id') id: string): Promise<PlanResponseDto> {
    return this.clientService.getClientPlan(id);
  }

  @Put(':id')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Update client information' })
  @ApiResponse({
    status: 200,
    description: 'Client updated successfully',
    type: ClientResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiResponse({
    status: 409,
    description: 'Client with this email already exists',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  @ApiBody({ type: UpdateClientDto })
  async updateClient(@Param('id') id: string, @Body() updateClientDto: UpdateClientDto): Promise<ClientResponseDto> {
    return this.clientService.updateClient(id, updateClientDto);
  }

  @Put(':id/plan')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Update client plan' })
  @ApiResponse({
    status: 200,
    description: 'Client plan updated successfully',
    type: PlanResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiResponse({
    status: 400,
    description: 'Cannot downgrade plan due to current user count',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  @ApiBody({ type: PlanDataDto })
  async updateClientPlan(@Param('id') id: string, @Body() planDataDto: PlanDataDto): Promise<PlanResponseDto> {
    return this.clientService.updateClientPlan(id, planDataDto);
  }

  @Delete(':id')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Delete client' })
  @ApiResponse({
    status: 204,
    description: 'Client deleted successfully',
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiResponse({
    status: 400,
    description: 'Cannot delete client with linked users',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  async deleteClient(@Param('id') id: string): Promise<void> {
    await this.clientService.deleteClient(id);
  }

  @Get(':id/users')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get users linked to a client' })
  @ApiResponse({
    status: 200,
    description: 'Client users retrieved successfully',
    type: PaginatedResponseDto<UserResponseDto>,
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  @ApiQuery({
    name: 'page',
    required: false,
    type: Number,
    description: 'Page number (default: 1)',
  })
  @ApiQuery({
    name: 'limit',
    required: false,
    type: Number,
    description: 'Items per page (default: 10)',
  })
  async getClientUsers(
    @Param('id') id: string,
    @Query('page', new ParseIntPipe({ optional: true })) page = 1,
    @Query('limit', new ParseIntPipe({ optional: true })) limit = 10,
  ): Promise<PaginatedResponseDto<UserResponseDto>> {
    return this.clientService.getClientUsers(id, page, limit);
  }

  @Post(':id/users/link')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Link a user to a client' })
  @ApiResponse({
    status: 200,
    description: 'User linked to client successfully',
  })
  @ApiResponse({
    status: 404,
    description: 'Client or user not found',
  })
  @ApiResponse({
    status: 400,
    description: 'Client has reached maximum user limit',
  })
  @ApiResponse({
    status: 409,
    description: 'User is already linked to client',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        userEmail: { type: 'string', format: 'email' },
      },
      required: ['userEmail'],
    },
  })
  async linkUserToClient(@Param('id') id: string, @Body('userEmail') userEmail: string): Promise<{ success: boolean }> {
    const success = await this.clientService.linkUserToClient(id, userEmail);
    return { success };
  }

  @Delete(':clientId/users/:userId')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Unlink a user from a client' })
  @ApiResponse({
    status: 204,
    description: 'User unlinked from client successfully',
  })
  @ApiResponse({
    status: 404,
    description: 'Client or user not found',
  })
  @ApiParam({
    name: 'clientId',
    type: 'string',
    description: 'Client ID',
  })
  @ApiParam({
    name: 'userId',
    type: 'number',
    description: 'User ID',
  })
  async unlinkUserFromClient(@Param('clientId') clientId: string, @Param('userId', ParseIntPipe) userId: number): Promise<void> {
    await this.clientService.unlinkUserFromClient(clientId, userId);
  }

  @Post('upgrade-user/:userId')
  // @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Upgrade a user to client' })
  @ApiResponse({
    status: 201,
    description: 'User upgraded to client successfully',
    type: ClientResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'User not found',
  })
  @ApiResponse({
    status: 409,
    description: 'User is already a client',
  })
  @ApiParam({
    name: 'userId',
    type: 'number',
    description: 'User ID to upgrade',
  })
  @ApiBody({ type: PlanDataDto })
  async upgradeUserToClient(@Param('userId', ParseIntPipe) userId: number, @Body() planData: PlanDataDto): Promise<ClientResponseDto> {
    this.logger.log(`Upgrading user with ID ${userId} to client with plan data: ${JSON.stringify(planData)}`);
    return this.clientService.upgradeUserToClient(userId, planData);
  }

  @Get(':id/validate-user-limit')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Validate if client can link more users' })
  @ApiResponse({
    status: 200,
    description: 'User link limit validation result',
    schema: {
      type: 'object',
      properties: {
        canLinkMoreUsers: { type: 'boolean' },
      },
    },
  })
  @ApiResponse({
    status: 404,
    description: 'Client not found',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'Client ID',
  })
  async validateUserLinkLimit(@Param('id', ParseIntPipe) id: string): Promise<{ canLinkMoreUsers: boolean }> {
    const canLinkMoreUsers = await this.clientService.validateUserLinkLimit(id);
    return { canLinkMoreUsers };
  }
}
