<template>
  <div>
    <div>
      <v-row justify="center">
        <v-dialog v-model="tfaDialog" persistent max-width="600px">
          <v-card>
            <v-card-title>
              <span class="text-h5">{{ authTwoFactor }}</span>
            </v-card-title>
            <v-card-text>
              <v-text-field
                v-model="pin"
                :label="authEnterPin"
                required
                :error-messages="pinError"
                autofocus
                @keyup.enter="tfaVerify"
              ></v-text-field>
            </v-card-text>
            <v-card-actions>
              <v-btn color="blue darken-1" text @click="cancelTfaVerify()">{{
                cancel
              }}</v-btn>
              <v-spacer></v-spacer>
              <v-btn
                color="blue darken-1"
                :disabled="pin == null || pin.length == 0"
                text
                @click="tfaVerify()"
                >{{ authVerifyCode }}</v-btn
              >
            </v-card-actions>
          </v-card>
        </v-dialog>
      </v-row>
      <v-row align="center" justify="center" class="mx-auto mt-sm-12 mb-16">
        <v-col cols="12" offset-md="4">
          <form>
            <v-row>
              <!-- Customer logo -->
              <v-col v-if="showCustomSmallLogo()" cols="12">
                <div class="text-center">
                  <img :src="mediumLogoUrl" />
                </div>
              </v-col>

              <v-col v-if="showCustomMediumLogo()" cols="7">
                <div class="text-center">
                  <img :src="largeLogoUrl" />
                </div>
              </v-col>

              <v-col v-if="showCustomLargeLogo()" cols="7">
                <div class="text-center">
                  <img :src="largeLogoUrl" />
                </div>
              </v-col>

              <!-- Small Sockeye logo -->
              <v-col v-if="showSmallBrandLogo()" cols="12">
                <!-- <v-img
                                    :src="require('@/assets/img/sockeye-64.png')"
                                    contain
                                    height="64"
                                ></v-img> -->
                <v-img
                  :src="require('../assets/logo.svg')"
                  contain
                  height="64"
                ></v-img>
              </v-col>
              <!-- Large Sockeye logo. -->
              <v-col v-if="showLargeBrandLogo()" cols="6" class="ml-16">
                <!-- <v-img
                                    :src="require('@/assets/img/sockey-128.png')"
                                    contain
                                    height="128"
                                ></v-img> -->
                <v-img
                  :src="require('../assets/logo.svg')"
                  contain
                  height="128"
                ></v-img>
              </v-col>
              <v-col v-if="formState.errorBoxMessage" cols="12" md="7">
                <gz-error
                  :error-box-message="formState.errorBoxMessage"
                ></gz-error>
              </v-col>

              <v-col cols="12" md="7">
                <v-text-field
                  id="username"
                  v-model="input.username"
                  v-focus
                  name="username"
                  prepend-icon="$sockiUser"
                  autofocus
                  autocomplete="off"
                  autocorrect="off"
                  autocapitalize="off"
                  spellcheck="false"
                  :error="errorBadCreds"
                  @keyup.enter="onEnterUserName"
                ></v-text-field>
              </v-col>
              <v-col cols="12" md="7">
                <v-text-field
                  id="password"
                  v-model="input.password"
                  name="password"
                  :append-outer-icon="reveal ? '$sockiEye' : '$sockiEyeSlash'"
                  prepend-icon="$sockiKey"
                  :type="reveal ? 'text' : 'password'"
                  :error="errorBadCreds"
                  @keyup.enter="login"
                  @click:append-outer="reveal = !reveal"
                ></v-text-field>
              </v-col>
              <v-col cols="12" md="7" mt-1 mb-5>
                <v-btn
                  color="primary"
                  value="LOGIN"
                  :data-cy="`loginbutton${errorBadCreds ? '_failedcreds' : ''}`"
                  @click="login()"
                >
                  <v-icon>$sockiSignIn</v-icon>
                </v-btn>
              </v-col>
            </v-row>
          </form>
        </v-col>
      </v-row>
      <v-footer color="primary" padless absolute>
        <div
          v-if="showFooterLogo()"
          style="text-align: center"
          class="mx-auto pa-4 mb-10 mb-sm-1 mt-n8"
        >
          <a
            href="https://ayanova.com"
            target="_blank"
            style="text-decoration: none"
            class="primary white--text text-caption"
          >
            <div v-if="showFooterLogo()" style="width: 100%" class="mx-auto">
              <v-img
                style="margin: 0 auto"
                :src="require('../assets/logo.svg')"
                contain
              ></v-img>
            </div>
            <div class="mx-auto">Sockeye {{ version }}</div>
            <div class="mx-auto">
              <span class="primary white--text text-caption">{{
                copyright
              }}</span>
            </div>
          </a>
        </div>
        <div
          v-else
          style="text-align: center"
          class="mx-auto pa-4 mb-1 mb-sm-1"
        >
          <a
            href="https://ayanova.com"
            target="_blank"
            style="text-decoration: none"
            class="primary white--text text-caption"
          >
            <div class="mx-auto">Sockeye {{ version }}</div>
            <div class="mx-auto">
              <span class="primary white--text text-caption">{{
                copyright
              }}</span>
            </div>
          </a>
        </div>
      </v-footer>
    </div>
  </div>
</template>
<script>
import { processLogin, processLogout } from "../api/authutil";
import sockeyeVersion from "../api/sockeye-version";
export default {
  data() {
    return {
      input: {
        username: null,
        password: null
      },
      tfaDialog: false,
      authTwoFactor: null,
      authEnterPin: null,
      authVerifyCode: null,
      authPinInvalid: null,
      cancel: null,
      pin: null,
      tt: null,
      pinError: null,
      loggedInWithKnownPassword: false,
      hasSmallLogo: false,
      hasMediumLogo: false,
      hasLargeLogo: false,
      smallLogoUrl: null,
      mediumLogoUrl: null,
      largeLogoUrl: null,
      errorBadCreds: false,
      reveal: false,
      formState: { errorBoxMessage: null }
    };
  },
  computed: {
    copyright() {
      return sockeyeVersion.copyright;
    },
    version() {
      return sockeyeVersion.version;
    }
  },
  async created() {
    const vm = this;
    window.$gz.eventBus.$emit("menu-change", {
      isMain: true,
      icon: "",
      title: null
    });
    //reset password redirects here with preset creds
    //this will help the user identify it and hopefully remember it
    if (vm.$route.params.presetLogin) {
      vm.input.username = vm.$route.params.presetLogin;
      vm.input.password = vm.$route.params.presetPassword;
    }

    vm.smallLogoUrl = window.$gz.api.logoUrl("small");
    vm.mediumLogoUrl = window.$gz.api.logoUrl("medium");
    vm.largeLogoUrl = window.$gz.api.logoUrl("large");
    try {
      let res = await window.$gz.api.get("notify/hello");
      if (res.data != null) {
        vm.input.username = "ss";
        vm.input.password = "ss";
        vm.reveal = true; //might as well show it since it's the default anyway

        //However, if the eval users exist then
        vm.hasSmallLogo = res.data.sl;
        vm.hasMediumLogo = res.data.ml;
        vm.hasLargeLogo = res.data.ll;
      }

      //Live eval from website redirects here with generated creds set
      // ...login?usr={username}&pw={pw}
      //anything in window.location.search is placed in the 'search' route parameter by app.vue for parsing here because they are lost when the redirect happens to the login form as it's actually app.vue that gets hit first not login
      //Note that the $route.query system does not work no matter what I tried and seems to be broken in vue router so have to do it ourselves from the
      //Handle search query params
      if (vm.$route.params.search != undefined) {
        let params = new URLSearchParams(vm.$route.params.search);
        if (params.has("usr")) {
          vm.input.username = params.get("usr");
          vm.input.password = params.get("pw");
        }
      }
    } catch (error) {
      //squash it, this isn't critical
    }
  },
  methods: {
    async tfaVerify() {
      //
      //send 2fa code to server if ok, then proceed as normal
      const vm = this;
      if (vm.pin && vm.pin != "") {
        vm.pinError = null;

        try {
          const res = await window.$gz.api.upsert(
            "auth/tfa-authenticate",
            {
              pin: vm.pin,
              tempToken: vm.tt
            },
            true
          );

          if (res.error) {
            //don't expect this to ever get called but just in case
            // throw new Error(res.error);
            throw new Error(window.$gz.errorHandler.errorToString(res, vm));
          }
          await this.step2(res);
        } catch (error) {
          //bad PIN?
          if (
            error.message &&
            error.message.includes("ErrorUserNotAuthenticated")
          ) {
            vm.pinError = vm.authPinInvalid;
            return;
          }
          //server closed by server state setting?
          if (error.code == 2000 || error.code == 2001 || error.code == 2006) {
            vm.formState.errorBoxMessage = error.message;
            return;
          }
          //probably here because server unresponsive.
          if (error.message) {
            let msg = error.message;
            if (
              msg.includes("NetworkError") ||
              msg.includes("Failed to fetch")
            ) {
              msg =
                "Could not connect to Sockeye server at " +
                window.$gz.api.APIUrl("") +
                "\r\nError: " +
                error.message;
            }
            //this just makes the error a little cleaner to remove the extraneous typeerror
            msg = msg.replace(" TypeError:", "");
            vm.formState.errorBoxMessage = msg;
            return;
          }
        }
      }
    },
    cancelTfaVerify() {
      const vm = this;
      vm.tt = null;
      vm.pin = null;
      vm.errorBadCreds = false;
      vm.pinError = [];
      vm.input.username = null;
      vm.input.password = null;
      vm.tfaDialog = false;
    },
    showFooterLogo() {
      return (
        this.showCustomSmallLogo() ||
        this.showCustomMediumLogo() ||
        this.showCustomLargeLogo()
      );
    },
    showSmallBrandLogo() {
      return !this.hasMediumLogo && this.$vuetify.breakpoint.smAndDown;
    },
    showLargeBrandLogo() {
      if (this.showSmallBrandLogo()) {
        return false;
      }
      if (this.showCustomSmallLogo()) {
        return false;
      }
      if (this.showCustomMediumLogo()) {
        return false;
      }
      if (this.showCustomLargeLogo()) {
        return false;
      }
      return true;
    },
    showCustomSmallLogo() {
      return this.hasMediumLogo && this.$vuetify.breakpoint.smAndDown;
    },
    showCustomMediumLogo() {
      return this.hasMediumLogo && this.$vuetify.breakpoint.mdOnly;
    },
    showCustomLargeLogo() {
      return this.hasLargeLogo && this.$vuetify.breakpoint.lgAndUp;
    },
    trialUserSelected(item) {
      this.input.password = item.p;
      this.input.username = item.l;
    },
    trialHelpClick: function() {
      //open help nav for trial login
      window.$gz.eventBus.$emit("menu-click", {
        key: "app:help",
        data: "sock-evaluate#sample-users"
      });
    },
    onEnterUserName: function() {
      //move focus to password
      document.getElementsByName("password")[0].focus();
    },
    async login() {
      const vm = this;

      if (vm.input.username != "" && vm.input.password != "") {
        vm.errorBadCreds = false;

        try {
          const res = await window.$gz.api.upsert(
            "auth",
            {
              login: vm.input.username,
              password: vm.input.password
            },
            true
          );
          if (res.error) {
            throw new Error(window.$gz.errorHandler.errorToString(res, vm));
          }
          //check for 2fa enabled, if so then need to do one more step before process login can be called
          if (res.data.tfa) {
            this.authTwoFactor = res.data.authTwoFactor;
            this.authEnterPin = res.data.authEnterPin;
            this.authVerifyCode = res.data.authVerifyCode;
            this.authPinInvalid = res.data.authPinInvalid;
            this.tt = res.data.tt;
            this.cancel = res.data.cancel;
            this.pin = null;
            //prompt for 2fa
            this.tfaDialog = true;
            return;
          }

          await this.step2(res);
        } catch (error) {
          if (
            error.message &&
            error.message.includes("License agreement consent required")
          ) {
            window.location.reload();
          }
          //bad creds?
          if (
            error.message &&
            error.message.includes("ErrorUserNotAuthenticated")
          ) {
            vm.errorBadCreds = true;
            return;
          }
          //server closed by server state setting?
          if (error.code == 2000 || error.code == 2001 || error.code == 2006) {
            vm.formState.errorBoxMessage = error.message;
            return;
          }
          //probably here because server unresponsive.
          if (error.message) {
            let msg = error.message;

            if (
              msg.includes("NetworkError") ||
              msg.includes("Failed to fetch")
            ) {
              msg =
                "Could not connect to Sockeye server at " +
                window.$gz.api.APIUrl("") +
                "\r\nError: " +
                error.message;
            }
            //this just makes the error a little cleaner to remove the extraneous typeerror
            msg = msg.replace(" TypeError:", "");
            vm.formState.errorBoxMessage = msg;
            return;
          }
        }
      }
    },
    async step2(res) {
      const vm = this;
      await processLogin(res.data, vm.loggedInWithKnownPassword);
      //check if support and updates has expired and is paid for license and show warning if so
      //but not to customer logins, that's just shaming and will anger people
      if (
        !vm.$store.getters.isCustomerUser &&
        vm.$store.state.globalSettings.maintenanceExpired &&
        (vm.$store.state.globalSettings.licenseStatus == 3 ||
          vm.$store.state.globalSettings.licenseStatus == 4)
      ) {
        (async function() {
          await window.$gz.dialog.displayLTModalNotificationMessage(
            "MaintenanceExpiredNote",
            "MaintenanceExpired",
            "error",
            "https://ayanova.com/docs/adm-license/#maintenance-expired-message"
          );
        })();
      }

      const toPath = vm.$route.params.topath; //set in app.vue::mounted
      if (toPath != undefined) {
        //open the url indicated
        vm.$router.push(vm.$route.params.topath);
      } else {
        vm.$router.push(vm.$store.state.homePage);
      }
    }
  },
  beforeRouteEnter(to, from, next) {
    //very important as this in conjunction with the menu options means
    //navigation guards work properly by just sending people here
    next(() => {
      processLogout();
      next();
    });
  }
};
</script>
