import * as plugins from '../plugins.js';
import { LoginSessionManager } from './classes.loginsessionmanager.js';
import { User } from './classes.user.js';

/**
 * a LoginSession keeps track of a login over the whole time of the user being loggedin
 */
@plugins.smartdata.Manager()
export class LoginSession extends plugins.smartdata.SmartDataDbDoc<
  LoginSession,
  plugins.idpInterfaces.data.ILoginSession,
  LoginSessionManager
> {
  // ======
  // static
  // ======
  public static async createLoginSessionForUser(userArg: User, deleteOtherSessions = false) {
    const loginSession = new LoginSession();
    loginSession.id = plugins.smartunique.shortId();
    loginSession.data.userId = userArg.id;
    await loginSession.save();
    return loginSession;
  }

  public static async clearLoginSessionsForUser(userArg: User) {
    // lets find existing sessions
    const existingSessions = await LoginSession.getInstances({
      id: userArg.id,
    });

    for (const existingSession of existingSessions) {
      await existingSession.delete();
    }
  }

  public static async getLoginSessionBySessionId(sessionIdArg: string) {
    return await LoginSession.getInstance({
      id: sessionIdArg,
    });
  }

  public static async getLoginSessionByRefreshToken(refreshTokenArg: string) {
    const loginSession = await LoginSession.getInstance({
      data: {
        refreshToken: refreshTokenArg,
      },
    });
    return loginSession;
  }

  // ========
  // INSTANCE
  // ========
  @plugins.smartdata.unI()
  public id: string;

  @plugins.smartdata.svDb()
  public data: plugins.idpInterfaces.data.ILoginSession['data'] = {
    userId: null,
    validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ weeks: 1 }),
    invalidated: false,
    refreshToken: null,
    deviceId: null
  };

  public transferToken: string;

  constructor() {
    super();
  }

  /**
   * invalidates a session
   */
  public async invalidate() {
    this.data.invalidated = true;
    await this.save();
  }

  /**
   * a refresh token is unique to a login session and ONLY created once per login session
   * @returns
   */
  public async getRefreshToken() {
    if (this.data.invalidated) {
      console.log('login session is invalidated. no refresh token can be generated.');
      return null;
    }
    if (!this.data.refreshToken) {
      this.data.refreshToken = plugins.smartunique.uni('refresh_');
    }
    await this.save();
    return this.data.refreshToken;
  }

  public async getTransferToken() {
    this.transferToken = plugins.smartunique.uni('transfer_');
    return this.transferToken;
  }

  public async validateRefreshToken(refreshTokenArg: string) {
    return this.data.refreshToken === refreshTokenArg;
  }

  public async validateTransferToken(transferTokenArg: string) {
    const result = this.transferToken === transferTokenArg;

    // a transfer token can only be used once, so we invalidate it here
    if (result) {
      this.transferToken = null;
    }
    return result;
  }
}
