import {
  BadRequestException,
  Body,
  ClassSerializerInterceptor,
  Controller,
  Inject,
  Post,
  Res,
  UnauthorizedException,
  UseInterceptors,
} from '@nestjs/common';
import { UserService } from 'api/common/user.service';
import { SkipAuth } from 'api/utils/decorator';
import { LoginDto } from './dtos/login.dto';
import { UserModel } from './models/user.model';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
import { RegisterDto } from './dtos/register.dto';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { CodeDto } from './dtos/code.dto';
import { comparePass, encryptPass } from '../../utils/encrypt';
import { MergeAuthDto } from './dtos/mergeAuth.dto';
import { EmailService } from '../email/email.service';
import { SettleInCodePrefix } from 'api/utils/constants';

@Controller('auth')
export class AuthController {
  constructor(
    private userService: UserService,
    private jwtService: JwtService,
    private emailService: EmailService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
  ) {}

  async loginEmailCode(email, code) {
    const cacheManager = this.cacheManager;
    const authCode = await cacheManager.get(email);
    if (!code) {
      throw new BadRequestException('验证码不存在');
    }
    if (authCode != code) {
      throw new BadRequestException('验证码不正确');
    }
    let user = await this.userService.findUserByEmail(email);
    if (!user) {
      user = await this.userService.save({
        email,
      });
    }
    return user;
  }

  async loginPass(email, password) {
    const user = await this.userService.findUserByEmail(email);
    if (user == null) {
      throw new UnauthorizedException('用户不存在');
    }
    if (!user.password) {
      throw new UnauthorizedException('未设置密码,无法使用密码登录');
    }
    if (!comparePass(password, user.password)) {
      throw new UnauthorizedException('账号或者密码不正确');
    }
    return user;
  }

  @UseInterceptors(ClassSerializerInterceptor)
  @Post('login')
  @SkipAuth()
  async login(
    @Body() loginDto: LoginDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    const { email, password } = loginDto;
    const user = await this.loginPass(email, password);
    const payload = {
      sub: user.id,
      roles: (user.roles && user.roles.split(',')) || [],
    };
    const accessToken = await this.jwtService.signAsync(payload);
    res.cookie('token', accessToken);
    return new UserModel(user);
  }

  @UseInterceptors(ClassSerializerInterceptor)
  @Post('register')
  @SkipAuth()
  async register(@Body() registerDto: RegisterDto) {
    const { email, password, authCode } = registerDto;
    const cacheManager = this.cacheManager;
    const code = await cacheManager.get(email);
    if (!code) {
      throw new BadRequestException('验证码不存在');
    }
    if (code != authCode) {
      throw new BadRequestException('验证码不正确');
    }
    const user = await this.userService.findUserByEmail(email);
    if (user) {
      throw new BadRequestException('用户已存在');
    }
    const saveUser = await this.userService.save({
      email,
      password: encryptPass(password),
    });
    this.cacheManager.del(email);
    return new UserModel(saveUser);
  }

  @Post('code')
  @SkipAuth()
  async code(@Body() codeDto: CodeDto) {
    const { email } = codeDto;
    const result = await this.emailService.sendValidecode(email);
    if (!result) {
      throw new BadRequestException('获取验证码失败');
    }
    await this.cacheManager.set(email, result, 360000);
    return true;
  }

  @Post('settlein/code')
  async settleInCode(@Body() codeDto: CodeDto) {
    const { email } = codeDto;
    const result = await this.emailService.sendSettleInCode(email);
    if (!result) {
      throw new BadRequestException('获取入驻验证码失败');
    }
    await this.cacheManager.set(SettleInCodePrefix + email, result, 360000);
    return true;
  }

  @UseInterceptors(ClassSerializerInterceptor)
  @Post('merge/login')
  @SkipAuth()
  async mergeLogin(
    @Body() mergeAuthDto: MergeAuthDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    const { email, code } = mergeAuthDto;
    const user = await this.loginEmailCode(email, code);
    // 判断是否是vip
    const roles = (user.roles && user.roles.split(',')) || [];
    const payload = {
      sub: user.id,
      roles,
    };
    const accessToken = await this.jwtService.signAsync(payload);
    res.cookie('token', accessToken);
    return new UserModel(user);
  }

  @Post('logout')
  async logout(@Res({ passthrough: true }) res: Response) {
    res.clearCookie('token');
    return true;
  }
}
