import request from "../../helper/request";
import sha from "../../helper/sha512";
import { setCookie, getCookie } from "../../helper/cookie";

export interface TwoFactor {
   id: string;
   name: string;
   type: TFATypes;
}

export enum TFATypes {
   OTC,
   BACKUP_CODE,
   U2F,
   APP_ALLOW,
}

// const Api = {
//    // twofactor: [{
//    //    id: "1",
//    //    name: "Backup Codes",
//    //    type: TFATypes.BACKUP_CODE
//    // }, {
//    //    id: "2",
//    //    name: "YubiKey",
//    //    type: TFATypes.U2F
//    // }, {
//    //    id: "3",
//    //    name: "Authenticator",
//    //    type: TFATypes.OTC
//    // }] as TwoFactor[],

// }

export interface IToken {
   token: string;
   expires: string;
}

function makeid(length) {
   var result = "";
   var characters =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
   var charactersLength = characters.length;
   for (var i = 0; i < length; i++) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
   }
   return result;
}

export default class Api {
   static salt: string;
   static login: IToken;
   static special: IToken;
   static username: string;

   static twofactor: any[];

   static getUsername() {
      return this.username || getCookie("username");
   }

   static async setUsername(
      username: string
   ): Promise<{ error: string | undefined }> {
      return request(
         "/api/user/login",
         {
            type: "username",
            username,
         },
         "POST"
      )
         .then((res) => {
            this.salt = res.salt;
            this.username = username;
            return {
               error: undefined,
            };
         })
         .catch((err) => {
            let error = err.message;
            return { error };
         });
   }

   static async setPassword(
      password: string
   ): Promise<{ error: string | undefined; twofactor?: any }> {
      const date = new Date().valueOf();
      let pw = sha(sha(this.salt + password) + date.toString());
      return request(
         "/api/user/login",
         {
            type: "password",
         },
         "POST",
         {
            username: this.username,
            password: pw,
            date,
         }
      )
         .then(({ login, special, tfa }) => {
            this.login = login;
            this.special = special;

            if (tfa && Array.isArray(tfa) && tfa.length > 0)
               this.twofactor = tfa;
            else this.twofactor = undefined;

            return {
               error: undefined,
            };
         })
         .catch((err) => {
            let error = err.message;
            return { error };
         });
   }

   static gettok() {
      return {
         login: this.login.token,
         special: this.special.token,
      };
   }

   static async sendBackup(id: string, code: string) {
      return request("/api/user/twofactor/backup", this.gettok(), "PUT", {
         code,
         id,
      })
         .then(({ login_exp, special_exp }) => {
            this.login.expires = login_exp;
            this.special.expires = special_exp;
            return {};
         })
         .catch((err) => ({ error: err.message }));
   }

   static async sendOTC(id: string, code: string) {
      return request("/api/user/twofactor/otc", this.gettok(), "PUT", {
         code,
         id,
      })
         .then(({ login_exp, special_exp }) => {
            this.login.expires = login_exp;
            this.special.expires = special_exp;
            return {};
         })
         .catch((error) => ({ error: error.message }));
   }

   static finish() {
      let d = new Date();
      d.setTime(d.getTime() + 30 * 24 * 60 * 60 * 1000); //Keep the username 30 days
      setCookie("username", this.username, d.toUTCString());

      setCookie(
         "login",
         this.login.token,
         new Date(this.login.expires).toUTCString()
      );
      setCookie(
         "special",
         this.special.token,
         new Date(this.special.expires).toUTCString()
      );

      let url = new URL(window.location.href);
      let state = url.searchParams.get("state");
      let red = "/";

      if (state) {
         let base64 = url.searchParams.get("base64");
         if (base64) red = atob(state);
         else red = state;
      }
      setTimeout(() => (window.location.href = red), 200);
   }
}
