import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Res,
  UploadedFile,
  UseGuards,
  UseInterceptors,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { InjectRepository } from '@nestjs/typeorm';
import { Response as ExpressResponse } from 'express';
import * as fs from 'fs';
import * as path from 'path';
import { saveError } from 'src/api-logs/api-error-log';
import { ApiLog } from 'src/api-logs/entities/api-log.entity';
import {
  errorResponse,
  successResponse,
  validationErrorMessage,
} from 'src/common/errors/response-config';
import { profilePictureConfig } from 'src/common/file upload/multer-config';
import { isEmpty } from 'src/common/helper';
import { AuthMiddleware } from 'src/common/middleware/auth.middleware';
import isValidUuidV4 from 'src/common/uuid validator/uuid-validate';
import { lan } from 'src/lan';
import { DataSource, Repository } from 'typeorm';
import { UpdateUserDto } from './dto/update-user.dto';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(
    private readonly userService: UserService,
    @InjectRepository(ApiLog)
    private readonly apiLogRepository: Repository<ApiLog>,
    private readonly connection: DataSource,
  ) {}

  @Get()
  @UseGuards(AuthMiddleware)
  async findAll(@Res() res: ExpressResponse) {
    try {
      const response = await this.userService.findAll();

      const removePassword = response.map((result) => {
        const { password, ...rest } = result;

        return rest;
      });

      if (response.length > 0) {
        res.send(
          successResponse(
            200,
            lan('common.data_retrieved_successfully'),
            removePassword,
          ),
        );
      } else {
        res.send(successResponse(404, lan('common.data_not_found')));
      }
    } catch (error) {
      res
        .status(500)
        .send(errorResponse(500, lan('common.internal_server_error')));

      saveError(error, this.apiLogRepository);
    }
  }

  @Get(':id')
  @UseGuards(AuthMiddleware)
  async findOne(@Param('id') id: string, @Res() res: ExpressResponse) {
    try {
      if (!isValidUuidV4(id)) {
        const errorMessage = lan('common.invalid_uuid_format');

        return res.send(errorResponse(400, errorMessage));
      }

      const result = await this.userService.findOne(id);

      delete result.password;

      if (isEmpty(result)) {
        return res.send(errorResponse(404, lan('common.data_not_found')));
      }

      res.send(
        successResponse(200, lan('common.data_retrieved_successfully'), result),
      );
    } catch (error) {
      res
        .status(500)
        .send(errorResponse(500, lan('common.internal_server_error')));
      saveError(error, this.apiLogRepository);
    }
  }

  @Patch(':id')
  @UseGuards(AuthMiddleware)
  @UseInterceptors(FileInterceptor('attachment', profilePictureConfig))
  @UsePipes(
    new ValidationPipe({
      exceptionFactory: validationErrorMessage,
      transform: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  )
  async update(
    @Param('id') id: string,
    @UploadedFile() attachment,
    @Body() updateUserDto: UpdateUserDto,
    @Res() res: ExpressResponse,
  ) {
    try {
      if (!isValidUuidV4(id)) {
        const errorMessage = lan('common.invalid_uuid_format');
        res.send(errorResponse(400, errorMessage));
        return;
      }

      const data = await this.userService.findOne(id);

      if (isEmpty(data)) {
        return res.send(errorResponse(404, lan('common.data_not_found')));
      }

      if (data) {
        if (attachment) {
          const attachmentUrl = `uploads/profile-picture/${attachment.filename}`;
          updateUserDto.profile_picture = attachmentUrl;
        }

        await this.userService.update(id, updateUserDto);
      }

      res.send(successResponse(200, lan('common.data_updated')));
    } catch (error) {
      res
        .status(500)
        .send(errorResponse(500, lan('common.internal_server_error')));

      saveError(error, this.apiLogRepository);
    }
  }

  @Delete(':id')
  @UseGuards(AuthMiddleware)
  async remove(@Param('id') id: string, @Res() res: ExpressResponse) {
    try {
      if (!isValidUuidV4(id)) {
        const errorMessage = lan('common.invalid_uuid_format');
        res.send(errorResponse(400, errorMessage));

        return;
      }

      const deleteAppliedJob = await this.userService.findOne(id);

      if (isEmpty(deleteAppliedJob)) {
        return res.send(errorResponse(404, lan('common.data_not_found')));
      }

      if (deleteAppliedJob) {
        if (deleteAppliedJob.profile_picture) {
          const resumeDeletePath = deleteAppliedJob.profile_picture.replace(
            process.env.DOMAIN,

            '',
          );

          const filePath = path.join(`public/${resumeDeletePath}`);

          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
          }
        }

        await this.userService.remove(id);

        res.send(successResponse(200, lan('common.data_deleted')));
      } else {
        res.status(404).send(errorResponse(404, lan('common.delete_error')));
      }
    } catch (error) {
      res
        .status(500)
        .send(errorResponse(500, lan('common.internal_server_error')));

      saveError(error, this.apiLogRepository);
    }
  }
}
