import { Body, Controller, Delete, Get, Logger, Param, Post, Put, UseGuards, Req, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
import { AuthGuard,  Roles, RolesGuard, RoleType } from '../../security';
import { PageRequest, Page } from '../../domain/base/pagination.entity';
import { <%= user.dtoClass%> } from '../../service/dto/user.dto';
import { HeaderUtil } from '../../client/header-util';
import { Request } from '../../client/request';
import { LoggingInterceptor } from '../../client/interceptors/logging.interceptor';
import {<%_ if (authenticationType === 'jwt') { _%> ApiBearerAuth, <%_ } else if (authenticationType === 'oauth2') { _%> ApiSecurity, <%_ } _%> ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
import { UserService } from '../../service/user.service';

@Controller('api/admin/users')
@UseGuards(AuthGuard, RolesGuard)
@UseInterceptors(LoggingInterceptor, ClassSerializerInterceptor)
<%_ if (authenticationType === 'jwt') { _%>
@ApiBearerAuth()
<%_ } else if (authenticationType === 'oauth2') { _%>
@ApiSecurity({})
<%_ } _%>
@ApiTags('user-resource')
export class UserController {
  logger = new Logger('UserController');

  constructor(private readonly userService: UserService) {}

  @Get('/')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ summary: 'Get the list of users' })
  @ApiResponse({
      status: 200,
      description: 'List all users',
      type: <%= user.dtoClass%>,
  })
  async getAllUsers(@Req() req: Request): Promise<<%= user.dtoClass%>[]> {
      const pageRequest: PageRequest = new PageRequest(
        req.query.page,
        req.query.size,
<%_ if (typeormOrderSupport) { _%>
        req.query.sort ?? '<%- user.primaryKey.name %>,ASC',
<%_ } _%>
      );
      const [results, count] = await this.userService.findAndCount({
          skip: +pageRequest.page * pageRequest.size,
          take: +pageRequest.size,
<%_ if (typeormOrderSupport) { _%>
          order: pageRequest.sort.asOrder(),
<%_ } _%>
      });
      HeaderUtil.addPaginationHeaders(req.res, new Page(results, count, pageRequest));
      return results;
  }

  @Post('/')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ summary: 'Create user' })
  @ApiResponse({
      status: 201,
      description: 'The record has been successfully created.',
      type: <%= user.dtoClass%>,
  })
  @ApiResponse({ status: 403, description: 'Forbidden.' })
  async createUser(@Req() req: Request, @Body() userDTO: <%= user.dtoClass%>): Promise<<%= user.dtoClass%>> {
      userDTO.password = userDTO.login;
      const created = await this.userService.save(userDTO, req.user?.login);
      HeaderUtil.addEntityCreatedHeaders(req.res, 'User', created.id);
      return created;
  }

  @Put('/')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ summary: 'Update user' })
  @ApiResponse({
      status: 200,
      description: 'The record has been successfully updated.',
      type: <%= user.dtoClass%>,
  })
  async updateUser(@Req() req: Request, @Body() userDTO: <%= user.dtoClass%>): Promise<<%= user.dtoClass%>> {
    const userOnDb = await this.userService.find({ where: { login: userDTO.login } });
    let updated = false;
    if (userOnDb && userOnDb.id) {
      userDTO.id = userOnDb.id;
      updated = true;
    } else {
      userDTO.password = userDTO.login;
    }
    const createdOrUpdated = await this.userService.update(userDTO, req.user?.login);
    if (updated) {
      HeaderUtil.addEntityUpdatedHeaders(req.res, 'User', createdOrUpdated.id);
    } else {
      HeaderUtil.addEntityCreatedHeaders(req.res, 'User', createdOrUpdated.id);
    }
    return createdOrUpdated;
  }

  @Get('/:login')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ summary: 'Get user' })
  @ApiResponse({
      status: 200,
      description: 'The found record',
      type: <%= user.dtoClass%>,
  })
  async getUser(@Param('login') loginValue: string): Promise<<%= user.dtoClass%>> {
      return await this.userService.find({ where: { login: loginValue } });
  }

  @Delete('/:login')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ summary: 'Delete user' })
  @ApiResponse({
      status: 204,
      description: 'The record has been successfully deleted.',
      type: <%= user.dtoClass%>
  })
  async deleteUser(@Req() req: Request, @Param('login') loginValue: string): Promise<<%= user.dtoClass%>> {
      HeaderUtil.addEntityDeletedHeaders(req.res, 'User', loginValue);
      const userToDelete = await this.userService.find({ where: { login: loginValue } });
      return await this.userService.delete(userToDelete);
  }
}
