import {
  Body,
  Controller,
  Delete,
  Get,
  Header,
  HttpCode,
  HttpStatus,
  Param,
  Post,
  Put,
  Query,
  Res,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiQuery, ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { successfulResult } from 'src/utils';
import { Filter } from 'src/utils/decorators/filter.decorator';
import { Limit } from 'src/utils/decorators/limit.decorator';
import { Page } from 'src/utils/decorators/page.decorator';
import { Sort } from 'src/utils/decorators/sort.decorator';
import { multerOptions } from 'src/utils/multer.options';
import { User } from '../../utils/decorators/user.decorator';
import { JwtAuthGuard } from '../auth/jwt/jwt.guard';
import { Permissions } from '../auth/permission/permissions.decorator';
import { PermissionsGuard } from '../auth/permission/permissions.guard';
import { PermissionsType } from '../role/entities/permission.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateAvatarDto } from './dto/update-avatar.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { UpdateWalletUserDto } from './dto/update-wallet-user.dto';
import { UserService } from './user.service';
import { ImportExcelDto } from './dto/import-excel.dto';

@ApiTags('User')
@Controller('users')
export class UserController {
  constructor(private userService: UserService) {}

  /**
   * -------------------------------------------------------
   * POST /users/import/excel/admin
   */
  @Post('/import/excel/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.IMPORT_EXCEL_TO_USER)
  @HttpCode(HttpStatus.CREATED)
  @ApiConsumes('multipart/form-data')
  @UseInterceptors(
    FileInterceptor('file', multerOptions('users', ['xlsx', 'xls'])),
  )
  async importExcel(
    @Body() dto: ImportExcelDto,
    @UploadedFile() file,
    @User('id') operatorUserId: string,
  ) {
    const results = await this.userService.importExcel(file, operatorUserId);
    return successfulResult(['لیست کاربران باموفقیت ثبت گردید'], results);
  }

  /**
   * -------------------------------------------------------
   */
  @Get('export/excel/admin')
  @Header('Content-Type', 'text/xlsx')
  @ApiQuery({ name: 'full_name', required: false })
  @ApiQuery({ name: 'mobile_phone', required: false })
  @ApiQuery({ name: 'national_code', required: false })
  @ApiQuery({ name: 'deleted', required: false, description: 'e.g. 1' })
  @ApiQuery({ name: 'is_active', required: false })
  @ApiQuery({ name: 'customer_id', required: false })
  @ApiQuery({
    name: 'has_wallet',
    required: false,
    description: 'e.g. 1',
  })
  @ApiQuery({
    name: 'role_id',
    required: false,
    description: 'User = 1 | Admin = 2 | ServiceMan = 3',
  })
  @ApiQuery({ name: 'sort', required: false, description: 'e.g. id:desc' })
  @ApiQuery({ name: 'limit', required: false, description: 'Default: 20' })
  @ApiQuery({ name: 'page', required: false, description: 'Default: 1' })
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.EXPORT_EXCEL_FROM_USER)
  async exportExcel(
    @Res() res: Response,
    @Filter([
      'deleted',
      ['is_active', 'isActive'],
      ['role_id', 'roleId'],
      ['customer_id', 'customerId'],
      ['national_code', 'nationalCode'],
    ])
    filters,
    @Query('full_name') fullName: string,
    @Query('mobile_phone') mobilePhone: string,
    @Query('has_wallet') hasWallet,
  ) {
    const result = await this.userService.exportExcel(filters, {
      fullName,
      mobilePhone,
      hasWallet: hasWallet === '1',
    });
    return res.download(`${result}`);
  }

  /**
   * -------------------------------------------------------
   * PUT /users/1/avatar/admin
   */
  @Put(':id/avatar/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.UPDATE_USER)
  @ApiConsumes('multipart/form-data')
  @UseInterceptors(FileInterceptor('file', multerOptions('avatars')))
  async updateAvatar(
    @Param('id') id: string,
    @Body() dto: UpdateAvatarDto,
    @UploadedFile() file,
  ) {
    await this.userService.updateAvatar(id, dto, file);
    return successfulResult(['آواتار کاربر مورد نظر، با موفقیت آپدیت شد']);
  }

  /**
   * -------------------------------------------------------
   * Put /users/1/admin
   */
  @Put(':id/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.UPDATE_USER)
  async updateUser(
    @Param('id') id: string,
    @Body() dto: UpdateUserDto,
    @User('id') operatorUserId: string,
  ) {
    await this.userService.updateUser(id, dto, operatorUserId);
    return successfulResult(['کاربر جدید با موفقیت آپدیت شد']);
  }

  /**
   * -------------------------------------------------------
   * Put /users/1/wallet/admin
   */
  @Put(':id/wallet/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.UPDATE_WALLET_USER)
  async updateWalletUser(
    @Param('id') id: string,
    @Body() dto: UpdateWalletUserDto,
  ) {
    await this.userService.updateWalletUser(id, dto);
    return successfulResult(['کیف پول کاربر با موفقیت آپدیت شد']);
  }

  /**
   * -------------------------------------------------------
   * show chart of users
   * GET /users/statistic/chart/admin
   */
  @Get('statistic/chart/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.GET_USER_STATISTICS)
  @ApiQuery({ name: 'from', required: true })
  @ApiQuery({ name: 'to', required: true })
  @ApiQuery({ name: 'type', required: true, enum: ['daily', 'monthly'] })
  async statisticChart(
    @Query('from') from,
    @Query('to') to,
    @Query('type') type,
  ) {
    const data = await this.userService.statisticChart(from, to, type);
    return successfulResult([], data);
  }

  /**
   * -------------------------------------------------------
   * Show count of users
   * GET /users/statistic/admin
   */
  @Get('statistic/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.GET_USER_STATISTICS)
  async statistic() {
    const data = await this.userService.statistic();
    return successfulResult([], data);
  }

  /**
   * -------------------------------------------------------
   */
  @Get('all/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.GET_USER)
  async all() {
    const data = await this.userService.getFull();
    return successfulResult([], data);
  }

  /**
   * -------------------------------------------------------
   * GET /users/1/admin
   */
  @Get(':id/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.GET_USER)
  async getById(@Param('id') userId: string) {
    const data = await this.userService.getById(userId);
    return successfulResult([], data);
  }

  /**
   * -------------------------------------------------------
   * GET /users/admin
   */
  @Get('admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.GET_USER)
  @ApiQuery({ name: 'full_name', required: false })
  @ApiQuery({ name: 'mobile_phone', required: false })
  @ApiQuery({ name: 'national_code', required: false })
  @ApiQuery({ name: 'deleted', required: false, description: 'e.g. 1' })
  @ApiQuery({ name: 'is_active', required: false })
  @ApiQuery({ name: 'customer_id', required: false })
  @ApiQuery({
    name: 'has_wallet',
    required: false,
    description: 'e.g. 1',
  })
  @ApiQuery({
    name: 'role_id',
    required: false,
    description: 'User = 1 | Admin = 2 | ServiceMan = 3',
  })
  @ApiQuery({ name: 'sort', required: false, description: 'e.g. id:desc' })
  @ApiQuery({ name: 'limit', required: false, description: 'Default: 20' })
  @ApiQuery({ name: 'page', required: false, description: 'Default: 1' })
  async getAll(
    @Page() page,
    @Limit(50) limit,
    @Sort() sorts,
    @Filter([
      'deleted',
      ['is_active', 'isActive'],
      ['role_id', 'roleId'],
      ['customer_id', 'customerId'],
      ['national_code', 'nationalCode'],
    ])
    filters,
    @Query('full_name') fullName: string,
    @Query('mobile_phone') mobilePhone: string,
    @Query('has_wallet') hasWallet,
  ) {
    const list = await this.userService.getAll(page, limit, sorts, filters, {
      fullName,
      mobilePhone,
      hasWallet: hasWallet === '1',
    });
    return successfulResult([], list);
  }

  /**
   * -------------------------------------------------------
   * POST /users/admin
   */
  @Post('admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.ADD_USER)
  @HttpCode(HttpStatus.CREATED)
  async addUser(
    @Body() dto: CreateUserDto,
    @User('id') operatorUserId: string,
  ) {
    const data = await this.userService.addUser(dto, operatorUserId);
    return successfulResult(['کاربر جدید با موفقیت ثبت شد'], data);
  }

  /**
   * -------------------------------------------------------
   * DELETE /user/1/admin
   */
  @Delete(':id/admin')
  @ApiBearerAuth()
  @UseGuards(JwtAuthGuard, PermissionsGuard)
  @Permissions(PermissionsType.DELETE_USER)
  async deleteUser(
    @Param('id') id: string,
    @User('id') operatorUserId: string,
  ) {
    await this.userService.deleteUser(id, operatorUserId);
    return successfulResult(['کاربر موردنظر، با موفقیت حذف شد']);
  }
}
