import { Server, Token, TwoFactor, UserRegisterInfo } from "@hibas123/openauth-internalapi";
import type { SessionContext } from "./index";
import LoginToken, { CheckToken } from "../../models/login_token";
import TwoFactorModel from "../../models/twofactor";
import moment = require("moment");

export default class SecurityService extends Server.SecurityService<SessionContext> {
   async GetTokens(ctx: SessionContext): Promise<Token[]> {
      if (!ctx.user) throw new Error("Not logged in");

      let raw_token = await LoginToken.find({
         user: ctx.user._id,
         valid: true,
      });
      let token = await Promise.all(
         raw_token
            .map<Promise<Token>>(async (token) => {
               await CheckToken(token);
               return {
                  id: token._id.toString(),
                  special: token.special,
                  ip: token.ip,
                  browser: token.browser,
                  isthis: token._id.equals(
                     token.special ? ctx.token.special._id : ctx.token.login._id
                  ),
               };
            })
            .filter((t) => t !== undefined)
      );

      return token
   }
   async RevokeToken(id: string, ctx: SessionContext): Promise<void> {
      if (!ctx.user) throw new Error("Not logged in");

      let token = await LoginToken.findById(id);
      if (!token || !token.user.equals(ctx.user._id))
         throw new Error("Invalid ID");
      token.valid = false;
      await LoginToken.save(token);
   }

   async GetTwofactorOptions(ctx: SessionContext): Promise<TwoFactor[]> {
      if (!ctx.user) throw new Error("Not logged in");


      let twofactor = await TwoFactorModel.find({ user: ctx.user._id, valid: true });
      let expired = twofactor.filter((e) =>
         e.expires ? moment().isAfter(moment(e.expires)) : false
      );
      await Promise.all(
         expired.map((e) => {
            e.valid = false;
            return TwoFactorModel.save(e);
         })
      );

      twofactor = twofactor.filter((e) => e.valid);
      let tfa = twofactor.map<TwoFactor>((e) => {
         return {
            id: e._id.toString(),
            name: e.name,
            tfatype: e.type as number,
            expires: e.expires?.valueOf()
         };
      });

      return tfa;
   }
}
