import { Args, Context, Mutation, Resolver } from '@nestjs/graphql';
import { Person } from '../models/Person';
import { Client } from '../../client';
import { PersonService } from '../person.service';
import { HttpException } from '@nestjs/common';
import {UUID} from '../../global/scalars/UUID'
import {OrganizerService} from '../../organizer/organizer.service'
import {EmailAddress} from '../../global/scalars/EmailAddress'
import {checkPassword, secureHash} from '../../generate'

@Resolver(() => Person)
export class PersonResolverM {
  constructor(
    private readonly service: PersonService,
  ) {}

  @Mutation(() => Person, { nullable: false })
  async login(
    @Context('client') client: Client,
    @Args('email', { nullable: true }) email?: string,
    @Args('passwort', { nullable: true }) passwort?: string,
    @Args('token', { nullable: true }) token?: string
  ): Promise<Person> {
    await client.login({email, passwort, token});
    const newtoken: string = client.getToken();

    if (!newtoken) {
      throw new HttpException('Logindaten falsch', 403);
    }

    const tmp = await this.service.findOneById(client.getUser()?._id);

    if (!!(tmp as unknown as any).confirmCode) {
      throw new HttpException('E-Mail-Adresse noch nicht bestätigt!', 403);
    }

    return tmp;
  }

  @Mutation(() => Person, { nullable: false })
  async PersonRegister(
    @Context('client') client: Client,
    @Args('organizer', { type: () => UUID, nullable: false }) organizer: UUID,
    @Args('givenName', { nullable: false }) givenName: string,
    @Args('familyName', { nullable: false }) familyName: string,
    @Args('email', { type: () => EmailAddress, nullable: false }) email: EmailAddress,
    @Args('passwort', { nullable: false }) passwort: string,
  ): Promise<Person> {
    const organizerService = new OrganizerService();
    const o = await organizerService.findOneById(organizer);

    if (!o) {
      throw new HttpException('Organizer-ID not found!', 404);
    }

    const tmp = await this.service.create(client, givenName, familyName, email, passwort);

    if (!o._admins) {
      organizerService.update(client, o._id, {$set: {_admins: [ tmp._id ] }}, {});
    } else if (o._admins.length === 0) {
      organizerService.update(client, o._id, {$push: {_admins: tmp._id }}, {});
    } else if (!o._pending) {
      organizerService.update(client, o._id, {$set: {_pending: [ tmp._id ] }}, {});
    } else {
      organizerService.update(client, o._id, {$push: {_pending: tmp._id }}, {});
    }

    // TODO: Mail verschicken

    return tmp;
  }

  @Mutation(() => Person, { nullable: true })
  async PersonConfirmMail(
    @Context('client') client: Client,
    @Args('email') email: string,
    @Args('confirmCode') confirmCode: string,
  ): Promise<Person> {
    const tmp = await this.service.find({email, confirmCode});

    if (tmp.length !== 1) {
      throw new HttpException('confirmCode not correct', 403);
    }

    this.service.update(client, tmp[0]._id, { $unset: { confirmCode } })
    return tmp[0];
  }

  @Mutation(() => Boolean, { nullable: false })
  async ChangePassword(
    @Context('client') client: Client,
    @Args('oldPassword', { nullable: false }) oldPassword: string,
    @Args('newPassword', { nullable: false }) newPassword: string,
  ): Promise<boolean> {
    if (!client.getUser()) {
      throw new HttpException('you need to be logged in to change your password!', 403);
    }

    const tmp = await this.service.findOneById(client.getUser()._id);

    if (!(await checkPassword(oldPassword, (tmp as unknown as any).passwort))) {
      throw new HttpException('old password wrong!', 403);
    }

    this.service.update(client, tmp._id, {$set: { passwort: await secureHash(newPassword) }});
    return true;
  }
}
