import {
  Body,
  Controller,
  Delete,
  Get,
  HttpStatus,
  ParseFilePipeBuilder,
  Patch,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UserService } from './user.service';
import { IUser, User } from '../../shared/decorators/auth/user.decorator';
import { RetrieveUserResponseDto } from './dtos/retrieve-user.dto';
import {
  ApiDefaultResponseStatus,
  ApiResponseStatuses,
} from '../../shared/decorators/swagger/api-response-statuses.decorator';
import { ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { IsPublic } from '../../shared/decorators/auth/is-public.decorator';
import { CreateUserDto, CreateUserResponseDto } from './dtos/create-user.dto';
import { FileInterceptor } from '@nestjs/platform-express';
import { ExistsByEmailDto } from './dtos/exists-by-email.dto';
import { UpdateUserDto } from './dtos/update-user.dto';
import { SingleUsernameDto } from '../../shared/dtos/users/single-username.dto';
import { SimpleNumberDto } from '../../shared/dtos/simple-number.dto';
import { RetrievePersonalIntakes } from './dtos/retrieve-personal-intakes.dto';

export const USER_CONTROLLER_PREFIX = 'user';

@ApiTags('User')
@Controller(USER_CONTROLLER_PREFIX)
export class UserController {
  constructor(private readonly _userService: UserService) {}

  @Get()
  @ApiDefaultResponseStatus(200, RetrieveUserResponseDto)
  @ApiResponseStatuses(400, 401, 404, 500, 502)
  async retrieveUser(
    @User() userPayload: IUser,
  ): Promise<RetrieveUserResponseDto> {
    return this._userService.retrieveUser(userPayload);
  }

  @Get('personal-intakes')
  @ApiDefaultResponseStatus(200, RetrievePersonalIntakes)
  @ApiResponseStatuses(401, 502)
  async retrievePersonalIntakes(
    @User() user: IUser,
  ): Promise<RetrievePersonalIntakes> {
    return this._userService.retrievePersonalIntakes(user);
  }

  @Get('count/liked-recipes')
  @ApiDefaultResponseStatus(200, SimpleNumberDto)
  @ApiResponseStatuses(401, 502)
  async countLikedRecipes(@User() user: IUser): Promise<SimpleNumberDto> {
    return this._userService.countLikedRecipes(user);
  }

  @Post('exists/username')
  @IsPublic()
  @ApiDefaultResponseStatus(200)
  @ApiResponseStatuses(404, 502)
  async existsByUsername(@Body() user: SingleUsernameDto) {
    return this._userService.existsByUsername(user);
  }

  @Post('exists/email')
  @IsPublic()
  @ApiDefaultResponseStatus(200)
  @ApiResponseStatuses(404, 502)
  async existsByEmail(@Body() user: ExistsByEmailDto) {
    return this._userService.existsByEmail(user);
  }

  @Post()
  @IsPublic()
  @ApiDefaultResponseStatus(201, CreateUserResponseDto)
  @ApiResponseStatuses(400, 401, 409, 500, 502)
  async createUser(
    @Body() user: CreateUserDto,
  ): Promise<CreateUserResponseDto> {
    return this._userService.createUser(user);
  }

  @Post('/upload/avatar')
  @ApiDefaultResponseStatus(200)
  @ApiResponseStatuses(400, 401, 500, 502)
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        image: {
          type: 'file',
        },
      },
      required: ['image'],
    },
  })
  @UseInterceptors(FileInterceptor('image'))
  async uploadAvatar(
    @User() user: IUser,
    @UploadedFile(
      new ParseFilePipeBuilder()
        .addMaxSizeValidator({
          maxSize: 8000000,
        })
        .build({
          errorHttpStatusCode: HttpStatus.BAD_REQUEST,
        }),
    )
    image: Express.Multer.File,
  ) {
    return this._userService.uploadAvatar(user, image);
  }

  @Patch()
  @ApiDefaultResponseStatus(200, RetrieveUserResponseDto)
  @ApiResponseStatuses(400, 401, 409, 404, 500, 502)
  async updateUser(
    @Body() user: UpdateUserDto,
    @User() userPayload: IUser,
  ): Promise<RetrieveUserResponseDto> {
    return this._userService.updateUser(user, userPayload);
  }

  @Delete('/upload/avatar')
  @ApiDefaultResponseStatus(200)
  @ApiResponseStatuses(401, 404, 502)
  async deleteAvatar(@User() user: IUser) {
    return this._userService.deleteAvatar(user);
  }

  @Delete()
  @ApiDefaultResponseStatus(200)
  @ApiResponseStatuses(401, 502)
  async deleteUser(@User() user: IUser) {
    return this._userService.deleteUser(user);
  }
}
