import { Body, ClassSerializerInterceptor, Controller, Delete, Get, Logger, Param, Post as PostMethod, Put, UseGuards, Req, UseInterceptors } from '@nestjs/common';
import { <% if (authenticationType === 'jwt') { _%> ApiBearerAuth, <% } else if (authenticationType === 'oauth2') { _%> ApiOAuth2Auth, <% } _%> ApiUseTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
import { <%= asDto(entityClass) %> } from '../dto/<%= entityFileName %>.dto';
import { <%= entityClass %>Interactor } from '../../domain/interactors/<%= entityFileName %>.interactor';
import { Page, PageRequest, SortDirection } from '../dto/base/pagination.dto';
import { AuthGuard,  Roles, RolesGuard, RoleType } from '../../security';
import { HeaderUtil } from '../../client/header-util';
import { Request } from '../../client/request';
import { LoggingInterceptor } from '../../client/interceptors/logging.interceptor';
import { <%=asEntity(entityClass)%>Mapper } from '../mapper/<%= entityFileName %>.mapper';

<%_
const pkType = getPkType(databaseType) === 'Long' ? 'number' : 'string';
_%>

@Controller('api/<%= entityApiUrl %>')
@UseGuards(AuthGuard, RolesGuard)
@UseInterceptors(LoggingInterceptor, ClassSerializerInterceptor)
<%_ if (authenticationType === 'jwt') { _%>
@ApiBearerAuth()
<%_ } else if (authenticationType === 'oauth2') { _%>
@ApiOAuth2Auth()
<%_ } _%>
@ApiUseTags('<%= entityApiUrl %>')
export class <%= entityClass %>Controller {
  logger = new Logger('<%= entityClass %>Controller');

  constructor(private readonly <%= asEntity(entityInstance) %>Interactor: <%= entityClass %>Interactor) {}


  @Get('/')
  @Roles(RoleType.USER)
  @ApiResponse({
    status: 200,
    description: 'List all records',
    type: <%= asDto(entityClass) %>,
  })
  async getAll(@Req() req: Request): Promise<<%= asDto(entityClass) %> []>  {
    const sortField = req.query.sort || 'id,asc';
    const [property, direction] = sortField.split(',');
    const pageRequest: PageRequest = new PageRequest(req.query.page, req.query.size, property, SortDirection[direction]);
    const [results, count] = await this.<%= asEntity(entityInstance) %>Interactor.findAndCount({
      skip: +pageRequest.page * pageRequest.size,
      take: +pageRequest.size,
      order: pageRequest.sort.asOrder(),
    });
    HeaderUtil.addPaginationHeaders(req.res, new Page(results, count, pageRequest));
    return <%=asEntity(entityClass)%>Mapper.fromModelsToDTOs(results);
  }

  @Get('/:id')
  @Roles(RoleType.USER)
  @ApiResponse({
    status: 200,
    description: 'The found record',
    type: <%= asDto(entityClass) %>,
  })
  async getOne(@Param('id') id: <%= pkType %>): Promise<<%= asDto(entityClass) %>>  {
    const result = await this.<%= asEntity(entityInstance) %>Interactor.findById(id);
    return <%=asEntity(entityClass)%>Mapper.fromModelToDTO(result);
  }

  @PostMethod('/')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ title: 'Create <%= asEntity(entityInstance) %>' })
  @ApiResponse({
    status: 201,
    description: 'The record has been successfully created.',
    type: <%= asDto(entityClass) %>,
  })
  @ApiResponse({ status: 403, description: 'Forbidden.' })
  async post(@Req() req: Request, @Body() <%= asEntity(entityInstance) %>DTO: <%= asDto(entityClass) %>): Promise<<%= asDto(entityClass) %>>  {
    const <%= asEntity(entityInstance) %> = <%=asEntity(entityClass)%>Mapper.fromDTOtoModel(<%= asEntity(entityInstance) %>DTO);
    const created = await this.<%= asEntity(entityInstance) %>Interactor.save(<%= asEntity(entityInstance) %>, req.user?.login);
    HeaderUtil.addEntityCreatedHeaders(req.res, '<%= entityClass %>', created.id);
    return <%=asEntity(entityClass)%>Mapper.fromModelToDTO(created);
  }

  @Put('/')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ title: 'Update <%= asEntity(entityInstance) %>' })
  @ApiResponse({
    status: 200,
    description: 'The record has been successfully updated.',
    type: <%= asDto(entityClass) %>,
  })
  async put(@Req() req: Request, @Body() <%= asEntity(entityInstance) %>DTO: <%= asDto(entityClass) %>): Promise<<%= asDto(entityClass) %>>  {
    HeaderUtil.addEntityCreatedHeaders(req.res, '<%= entityClass %>', <%= asEntity(entityInstance) %>DTO.id);
    const <%= asEntity(entityInstance) %> = <%=asEntity(entityClass)%>Mapper.fromDTOtoModel(<%= asEntity(entityInstance) %>DTO);
    const result = await this.<%= asEntity(entityInstance) %>Interactor.update(<%= asEntity(entityInstance) %>, req.user?.login);
    return <%=asEntity(entityClass)%>Mapper.fromModelToDTO(result);
  }

  @Put('/:id')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ title: 'Update <%= asEntity(entityInstance) %> with id' })
  @ApiResponse({
    status: 200,
    description: 'The record has been successfully updated.',
    type: <%= asDto(entityClass) %>,
  })
  async putId(@Req() req: Request, @Body() <%= asEntity(entityInstance) %>DTO: <%= asDto(entityClass) %>): Promise<<%= asDto(entityClass) %>>  {
    HeaderUtil.addEntityCreatedHeaders(req.res, '<%= entityClass %>', <%= asEntity(entityInstance) %>DTO.id);
    const <%= asEntity(entityInstance) %> = <%=asEntity(entityClass)%>Mapper.fromDTOtoModel(<%= asEntity(entityInstance) %>DTO);
    const result = await this.<%= asEntity(entityInstance) %>Interactor.update(<%= asEntity(entityInstance) %>, req.user?.login);
    return <%=asEntity(entityClass)%>Mapper.fromModelToDTO(result);
  }

  @Delete('/:id')
  @Roles(RoleType.ADMIN)
  @ApiOperation({ title: 'Delete <%= asEntity(entityInstance) %>' })
  @ApiResponse({
    status: 204,
    description: 'The record has been successfully deleted.',
    type: <%= asDto(entityClass) %>,
  })
  async deleteById(@Req() req: Request, @Param('id') id: <%= pkType %>): Promise<<%= asDto(entityClass) %>>  {
    HeaderUtil.addEntityDeletedHeaders(req.res, '<%= entityClass %>', id);
    const <%= asEntity(entityInstance) %>ToDelete = await this.<%= asEntity(entityInstance) %>Interactor.findById(id);
    const result = await this.<%= asEntity(entityInstance) %>Interactor.delete(<%= asEntity(entityInstance) %>ToDelete);
    return <%=asEntity(entityClass)%>Mapper.fromModelToDTO(result);
  }
}
