import { Body, Config, Controller, Inject, Param, Post, Get } from '@midwayjs/core';
import { ApiTags } from '@midwayjs/swagger';
import { LoginDTO, LoginType, LoginVO, UPwdDTO } from '../interface/login.interface';
import { LoginService } from '../service/login.service';
import { JwtService } from '@midwayjs/jwt';
import { Context } from '@midwayjs/koa';
const assert = require('assert');
import get = require('lodash/get');
import { UtilService } from '../service/util.service';
import { UserService } from '../service/system/user.service';
import { ErrorCode, ServiceError } from '../error/service.error';

@ApiTags(['登录服务'])
@Controller('/login')
export class LoginController {
  @Inject()
  loginService: LoginService;
  @Inject()
  jwtService: JwtService;
  @Inject()
  utilService: UtilService;
  @Inject()
  userSerivce: UserService;
  @Config('jwt.secret')
  jwtSecret;
  @Config('jwt.expiresIn')
  jwtExpiresIn;
  @Inject()
  ctx: Context;

  @Post('/reg/check', { routerName: '用户注册-验证码验证' })
  async regCodeCheck(@Body('phone') phone: string, @Body('checkCode') code: string) {
    if (!phone) throw new ServiceError(ErrorCode.PWD_NO_PHONE);
    if (!code) throw new ServiceError(ErrorCode.PWD_NO_CODE);
    await this.loginService.checkRegCode(phone, code);
  }

  @Post('/reg/code', { routerName: '用户注册-获取验证码' })
  async getRegCode(@Body('phone') phone: string) {
    if (!phone) throw new ServiceError(ErrorCode.PWD_NO_PHONE); // 缺少手机号
    const res = await this.userSerivce.checkPhone({ phone });
    if (!res) throw new ServiceError(ErrorCode.PHONE_IS_EXISTS);
    await this.loginService.sendRegCode(phone)
  }

  @Post('/pwd/reset', { routerName: '用户忘记密码-重置密码' })
  async pwdReset(@Body('id') id: number, @Body('password') password: string) {
    if (!id || !password) throw new ServiceError(ErrorCode.BODY_ERROR);
    // 检查是否有该用户
    const user = await this.userSerivce.fetch({ id }, { id: this.userSerivce.Opera.Equal });
    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
    await this.userSerivce.update({ id }, { password });
  }

  @Post('/pwd/check', { routerName: '用户忘记密码-验证码验证' })
  async pwdCodeCheck(@Body() body: object) {
    const type = get(body, 'type');
    const to = get(body, 'to');
    const code = get(body, 'checkCode');
    if (!code) throw new ServiceError(ErrorCode.PWD_NO_CODE); // 缺少密码找回验证码
    if (!type) throw new ServiceError(ErrorCode.PWD_NO_TYPE); //缺少找回方式
    else if (type !== 'phone' && type !== 'email') throw new ServiceError(ErrorCode.PWD_ERROR_TYPE); // 找回方式错误
    if (type === 'phone' && !to) throw new ServiceError(ErrorCode.PWD_NO_PHONE); // 缺少手机号码
    else if (type === 'email' && !to) throw new ServiceError(ErrorCode.PWD_NO_EMAIL); //缺少邮箱地址
    await this.loginService.checkPwdCode(type, to, code);
    // 检查是否有该用户
    const user = await this.userSerivce.fetch({ [type]: to }, { phone: this.userSerivce.Opera.Equal, email: this.userSerivce.Opera.Equal });
    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
    // 将id返回给前端,直接做修改密码用
    const id = get(user, 'id');
    return id;
  }

  @Post('/pwd/code', { routerName: '用户忘记密码-获取验证码' })
  async getPwdCode(@Body() body: object) {
    const type = get(body, 'type');
    const to = get(body, 'to');
    if (!type) throw new ServiceError(ErrorCode.PWD_NO_TYPE); //缺少找回方式
    else if (type !== 'phone' && type !== 'email') throw new ServiceError(ErrorCode.PWD_ERROR_TYPE); // 找回方式错误
    if (type === 'phone' && !to) throw new ServiceError(ErrorCode.PWD_NO_PHONE); // 缺少手机号码
    else if (type === 'email' && !to) throw new ServiceError(ErrorCode.PWD_NO_EMAIL); //缺少邮箱地址
    // 检查是否有该用户
    const user = await this.userSerivce.fetch({ [type]: to }, { phone: this.userSerivce.Opera.Equal, email: this.userSerivce.Opera.Equal });
    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
    // 有用户再发
    await this.loginService.sendPwdCode(type, to);
  }

  @Post('/sms/code', { routerName: '用户登录-获取登录验证码' })
  async getSmsCode(@Body('phone') phone: string) {
    // 先用phone找下用户,没有先返回去
    const user = await this.userSerivce.fetch({ phone }, { phone: this.userSerivce.Opera.Equal });
    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
    await this.loginService.sendSmsLoginCode(phone);
  }

  @Post('/sms/login', { routerName: '用户登录-通过手机验证码登录' })
  async smsLogin(@Body() body: object) {
    await this.loginService.valiSmsCode(body);
    // 没有中断,就是没有问题,直接通过phone查出来用户然后返回
    const phone = get(body, 'phone');
    const user = await this.userSerivce.fetch({ phone }, { phone: this.userSerivce.Opera.Equal });
    user.role = [LoginType.User];
    let vo = new LoginVO(user);
    vo = JSON.parse(JSON.stringify(vo));
    vo.login_code = await this.loginService.onePointLogin(vo);
    const token = await this.jwtService.sign(vo, this.jwtSecret);
    return token;
  }

  /**
   * 账密登录
   * @param data 用户名和密码
   * @param type 用户类型
   */
  @Post('/:type', { routerName: '登录' })
  async toLogin(@Body() data: LoginDTO, @Param('type') type: string) {
    const user = await this.loginService.loginByAccount(data, LoginType[type]);
    // 超级管理员不需要设置角色,部门,直接给
    if (type === 'Admin' && user.is_super === '0') user.role = [type];
    let vo = new LoginVO(user);
    vo = JSON.parse(JSON.stringify(vo));
    vo.login_code = await this.loginService.onePointLogin(vo);
    const token = await this.jwtService.sign(vo, this.jwtSecret);
    return token;
  }

  /**
   * TODO:微信小程序登录
   * @param type 用户类型
   */
  @Post('/wxapp/:type')
  async wxAppLogin(@Body('openid') openid: string, @Param('type') type: string) {
    if (!openid) assert(openid, '缺少微信唯一标识信息');
    const user = await this.loginService.wxAppLogin(openid, LoginType[type]);
    let vo = new LoginVO(user);
    vo = JSON.parse(JSON.stringify(vo));
    vo.login_code = await this.loginService.onePointLogin(vo);
    const token = await this.jwtService.sign(vo, this.jwtSecret);
    return token;
  }
  /**
   * 修改密码
   * @param data 修改密码所需数据
   * @param type 账户类型
   */
  @Post('/updatePwd/:type', { routerName: '修改密码' })
  async updatePwd(@Body() data: UPwdDTO, @Param('type') type: string) {
    await this.loginService.updatePwd(data, LoginType[type]);
    return 'ok';
  }

  @Post('/resetPwd/:type', { routerName: '重置密码' })
  async resetPwd(@Body('id') id: number, @Param('type') type: string) {
    // 随机密码
    const data = new UPwdDTO();
    data.id = id;
    data.password = this.utilService.randomStr();
    await this.loginService.updatePwd(data, LoginType[type]);
    return data.password;
  }

  @Get('/analysis')
  async analysisToken() {
    const token = get(this.ctx, 'request.header.token');
    assert(token, '缺少token信息');
    const result = await this.jwtService.decodeSync(token);
    return result;
  }
}
