import * as plugins from '../plugins.js';
import { RegistrationSession } from './classes.registrationsession.js';
import { Reception } from './classes.reception.js';
import { logger } from './logging.js';

export class RegistrationSessionManager {
  public receptionRef: Reception;

  public registrationSessions = new plugins.lik.FastMap<RegistrationSession>();
  public typedRouter = new plugins.typedrequest.TypedRouter();

  constructor(receptionRefArg: Reception) {
    this.receptionRef = receptionRefArg;
    this.receptionRef.typedrouter.addTypedRouter(this.typedRouter);

    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FirstRegistration>(
        'firstRegistrationRequest',
        async (requestData) => {
          // check for exiting User
          const existingUser = await this.receptionRef.userManager.CUser.getInstance({
            data: {
              email: requestData.email,
            },
          });
          if (existingUser) {
            this.receptionRef.receptionMailer.sendAlreadyRegisteredEmail(existingUser);
            throw new plugins.typedrequest.TypedResponseError(
              `We sent you an Email with more information.`
            );
          }
          // check for exiting SignupSession
          const existingSession = this.registrationSessions.getByKey(requestData.email);
          if (existingSession) {
            logger.log('warn', `destroyed old signupSession for ${requestData.email}`);
            existingSession.destroy();
          }

          // lets check the email before we create a signup session

          const newSignupSession = await RegistrationSession.createRegistrationSessionForEmail(
            this,
            requestData.email
          ).catch((e: plugins.typedrequest.TypedResponseError) => {
            console.log(e.errorText);
            throw e;
          });

          if (newSignupSession) {
            logger.log('info', `created signupSession for ${requestData.email}`);
            return {
              status: 'ok',
              testOnlyToken: process.env.TEST_MODE ? newSignupSession.unhashedEmailToken : null,
            };
          } else {
            return { status: 'not ok' };
          }
        }
      )
    );

    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_AfterRegistrationEmailClicked>(
        'afterRegistrationEmailClicked',
        async (requestData) => {
          console.log(requestData);
          const signupSession = await this.registrationSessions.find(async (itemArg) =>
            itemArg.validateEmailToken(requestData.token)
          );
          if (signupSession) {
            return {
              email: signupSession.emailAddress,
              status: 'ok',
            };
          } else {
            return {
              email: null,
              status: 'not ok',
            };
          }
        }
      )
    );

    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_SetDataForRegistration>(
        'setDataForRegistration',
        async (requestData) => {
          const registrationSession = await this.registrationSessions.find(async (itemArg) =>
            itemArg.validateEmailToken(requestData.token)
          );
          if (!registrationSession) {
            throw new plugins.typedrequest.TypedResponseError(
              'could not find a matching signupsession'
            );
          }

          if (requestData.userData.name) {
            registrationSession.collectedData.userData.name = requestData.userData.name;
          }

          if (requestData.userData.password) {
            registrationSession.collectedData.userData.password = requestData.userData.password;
          }

          return {
            status: 'ok',
          };
        }
      )
    );

    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_MobileVerificationForRegistration>(
        'mobileVerificationForRegistration',
        async (requestData) => {
          const registrationSession = await this.registrationSessions.find(async (itemArg) =>
            itemArg.validateEmailToken(requestData.token)
          );
          if (!registrationSession) {
            throw new plugins.typedrequest.TypedResponseError(
              'could not find a matching signupsession'
            );
          }

          // check prerequisites
          if (registrationSession.status === 'announced') {
            throw new plugins.typedrequest.TypedResponseError(
              'You must validate the email address first'
            );
          }

          if (requestData.mobileNumber) {
            registrationSession.status = 'emailValidated';
            registrationSession.collectedData.userData.mobileNumber = requestData.mobileNumber;
            await registrationSession.sendValidationSms();
            return {
              messageSent: true,
              testOnlySmsCode: process.env.TEST_MODE ? registrationSession.smsCode : null,
            };
          }

          if (requestData.verificationCode) {
            const validationResult = registrationSession.validateSmsCode(
              requestData.verificationCode
            );
            return {
              verficationCodeOk: validationResult,
            };
          }

          throw new plugins.typedrequest.TypedResponseError(
            'you misused the purpose of this TypedHandler'
          );
        }
      )
    );

    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FinishRegistration>(
        'finishRegistration',
        async (requestData) => {
          const registrationSession = await this.registrationSessions.find(async (itemArg) =>
            itemArg.validateEmailToken(requestData.token)
          );
          if (!registrationSession) {
            throw new plugins.typedrequest.TypedResponseError(
              'could not find a matching signupsession'
            );
          }

          const resultingUser = await registrationSession.manifestUserWithAccountData();
          registrationSession.destroy();
          this.receptionRef.receptionMailer.sendWelcomeEMail(resultingUser);
          return {
            accountData: {
              id: resultingUser.id,
              data: {
                email: resultingUser.data.email,
                name: resultingUser.data.name,
                username: resultingUser.data.username,
              },
            },
            status: 'ok',
          };
        }
      )
    );
  }
}
