import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  UseInterceptors,
  UploadedFile,
  ParseUUIDPipe,
  HttpCode,
  HttpStatus,
  ForbiddenException,
  BadRequestException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname, join } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { randomUUID } from 'crypto';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiResponse,
  ApiParam,
  ApiConsumes,
} from '@nestjs/swagger';
import { UsersService, UserRecord } from './users.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles, UserRole } from '../../common/decorators/roles.decorator';
import { CurrentUser, JwtPayload } from '../../common/decorators/current-user.decorator';

const AVATARS_DIR = join(process.cwd(), '..', '..', 'data', 'avatars');

@ApiTags('Users')
@ApiBearerAuth()
@Controller('users')
@UseGuards(JwtAuthGuard)
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  @UseGuards(RolesGuard)
  @Roles(UserRole.CLUB_ADMIN, UserRole.SUPER_ADMIN)
  @ApiOperation({ summary: 'List all users for the current club' })
  @ApiResponse({ status: 200, description: 'List of users' })
  async findAll(@CurrentUser() user: JwtPayload) {
    return this.usersService.findAllByClub(user.clubId);
  }

  @Post()
  @UseGuards(RolesGuard)
  @Roles(UserRole.CLUB_ADMIN, UserRole.SUPER_ADMIN)
  @ApiOperation({ summary: 'Create a new employee' })
  @ApiResponse({ status: 201, description: 'Employee created' })
  async create(
    @CurrentUser() user: JwtPayload,
    @Body()
    dto: { name: string; phone: string; role: string; password: string; departmentId?: string },
  ) {
    return this.usersService.createUser(user.clubId, dto);
  }

  @Get('staff')
  @ApiOperation({ summary: 'Get active staff members for the current club' })
  @ApiResponse({ status: 200, description: 'List of staff members' })
  async getStaff(@CurrentUser() user: JwtPayload, @Query('search') search?: string) {
    return this.usersService.findStaff(user.clubId, search);
  }

  @Get('trainers')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({ summary: 'Get all trainers for the current club' })
  @ApiResponse({ status: 200, description: 'List of trainers' })
  async getTrainers(@CurrentUser() user: JwtPayload): Promise<UserRecord[]> {
    return this.usersService.findTrainersByClub(user.clubId);
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get user detail by ID (UUID) or number (int)' })
  @ApiParam({ name: 'id', description: 'User UUID or sequential number' })
  @ApiResponse({ status: 200, description: 'User detail' })
  async findById(@CurrentUser() currentUser: JwtPayload, @Param('id') id: string) {
    if (/^\d+$/.test(id)) {
      return this.usersService.findByNumber(currentUser.clubId, parseInt(id, 10));
    }
    return this.usersService.findByIdDetailed(currentUser.clubId, id);
  }

  @Patch(':id')
  @ApiOperation({ summary: 'Update an employee' })
  @ApiParam({ name: 'id', description: 'User UUID' })
  @ApiResponse({ status: 200, description: 'Employee updated' })
  async update(
    @CurrentUser() currentUser: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @Body()
    dto: {
      name?: string;
      phone?: string;
      role?: string;
      departmentId?: string;
      email?: string;
      roomId?: string;
      comment?: string;
    },
  ) {
    this.checkEditPermission(currentUser, id);
    return this.usersService.updateUser(id, dto);
  }

  @Post(':id/password')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Change user password' })
  @ApiParam({ name: 'id', description: 'User UUID' })
  async changePassword(
    @CurrentUser() currentUser: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: { oldPassword?: string; newPassword: string },
  ) {
    const isSelf = currentUser.sub === id;
    const isAdmin = [UserRole.CLUB_ADMIN, UserRole.SUPER_ADMIN].includes(
      currentUser.role as UserRole,
    );
    if (!isSelf && !isAdmin) {
      throw new ForbiddenException('Недостаточно прав');
    }
    return this.usersService.changePassword(id, currentUser.sub, currentUser.role, dto);
  }

  @Post(':id/avatar')
  @ApiOperation({ summary: 'Upload user avatar' })
  @ApiParam({ name: 'id', description: 'User UUID' })
  @ApiConsumes('multipart/form-data')
  @UseInterceptors(
    FileInterceptor('avatar', {
      storage: diskStorage({
        destination: (_req, _file, cb) => {
          if (!existsSync(AVATARS_DIR)) mkdirSync(AVATARS_DIR, { recursive: true });
          cb(null, AVATARS_DIR);
        },
        filename: (_req, file, cb) => {
          cb(null, `${randomUUID()}${extname(file.originalname)}`);
        },
      }),
      limits: { fileSize: 5 * 1024 * 1024 },
      fileFilter: (_req, file, cb) => {
        if (['image/jpeg', 'image/png', 'image/webp'].includes(file.mimetype)) {
          cb(null, true);
        } else {
          cb(
            new BadRequestException('Допустимые форматы: JPEG, PNG, WebP') as unknown as Error,
            false,
          );
        }
      },
    }),
  )
  async uploadAvatar(
    @CurrentUser() currentUser: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @UploadedFile() file: Express.Multer.File,
  ) {
    this.checkEditPermission(currentUser, id);
    if (!file) throw new BadRequestException('Файл не загружен');
    return this.usersService.updateAvatar(id, `/avatars/${file.filename}`);
  }

  @Delete(':id')
  @UseGuards(RolesGuard)
  @Roles(UserRole.CLUB_ADMIN, UserRole.SUPER_ADMIN)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Deactivate an employee' })
  @ApiParam({ name: 'id', description: 'User UUID' })
  async remove(@Param('id', ParseUUIDPipe) id: string) {
    return this.usersService.deleteUser(id);
  }

  private checkEditPermission(currentUser: JwtPayload, targetUserId: string): void {
    const isSelf = currentUser.sub === targetUserId;
    const isAdmin = [UserRole.CLUB_ADMIN, UserRole.SUPER_ADMIN].includes(
      currentUser.role as UserRole,
    );
    if (!isSelf && !isAdmin) {
      throw new ForbiddenException('Недостаточно прав для редактирования');
    }
  }
}
