<template>
  <q-layout view="hHh lpR fFf">
    <img
      v-if="landspace"
      src="pad/login_background.jpg"
      class="fit"
      style="position: fixed"
    />
    <div
      v-if="landspace"
      class="full-height text-h4 text-white text-center text-weight-bold"
      style="position: fixed; writing-mode: vertical-lr; left: 56.5%"
    >
      <span> {{ $t("welcome") }}{{ $t(" ") }}{{ $t("login") }} </span>
    </div>
    <div
      v-if="landspace"
      class="full-height text-h4 text-white text-center text-weight-bold"
      style="position: fixed; writing-mode: vertical-lr; left: 61.5%"
    >
      <span>{{ $t("_SOFT_PAD_LOGIN_TITLE_") }}</span>
    </div>

    <q-page-container>
      <q-page
        class="row items-center"
        style="position: ; /*fixed*/"
        :class="landspace ? '' : 'justify-evenly'"
        :style="landspace ? { left: '7%' } : {}"
      >
        <q-card
          class="transparent no-box-shadow"
          :style="{
            width: (landspace ? 48 : 70) + 'vw',
            top: landspace ? '-2vh' : 'unset',
          }"
        >
          <div v-if="!landspace">
            <q-card-section class="text-center text-h6">
              <span class="text-accent">
                {{ $t("login") }}
              </span>
            </q-card-section>
            <q-separator />
          </div>
          <q-card-section class="fit">
            <q-form ref="login_form" @submit="onSubmit" @reset="onReset">
              <q-list class="fit text-h6">
                <q-item
                  v-if="
                    ($q.platform.is.android && $q.platform.is.capacitor) ||
                    $store.state.advanced_debug
                  "
                >
                  <q-item-section>
                    <q-input
                      :autofocus="!data.ip_address"
                      :loading="data.loading"
                      :disable="data.loading"
                      v-model="data.ip_address"
                      input-class="text-accent text-h6"
                      color="accent"
                      :dark="landspace"
                      :placeholder="$t('please input server ip address')"
                      lazy-rules
                      :rules="[
                        (val) =>
                          (val && val.length > 0) ||
                          $t('Please type something'),
                        (val) =>
                          isHost(val) || $t('Please input vaild ip address'),
                      ]"
                      @keydown="
                        (evt) => {
                          if (evt.keyCode == 13) {
                            $refs?.user_name?.focus();
                          }
                        }
                      "
                    >
                      <template v-slot:prepend>
                        <q-icon name="img:pad/login/server_ip.png" />
                      </template>
                      <template v-if="data.ip_address" v-slot:append>
                        <q-icon
                          name="cancel"
                          @click.stop="data.ip_address = null"
                          class="cursor-pointer"
                        />
                      </template>
                    </q-input>
                  </q-item-section>
                  <q-item-section avatar v-if="$q.platform.is.capacitor">
                    <q-btn
                      flat
                      round
                      icon="search"
                      color="accent"
                      @click="show_search_dialog = true"
                    />
                  </q-item-section>
                </q-item>

                <q-item>
                  <q-item-section>
                    <q-input
                      :autofocus="!data.user_name"
                      ref="user_name"
                      :loading="data.loading"
                      :disable="data.loading"
                      v-model="data.user_name"
                      input-class="text-accent text-h6"
                      color="accent"
                      :dark="landspace"
                      :placeholder="$t('please input user name')"
                      lazy-rules
                      :rules="[
                        (val) =>
                          (val && val.length > 0) ||
                          $t('Please type something'),
                      ]"
                      @keydown="
                        (evt) => {
                          if (evt.keyCode == 13) {
                            $refs?.password_input?.focus();
                          }
                        }
                      "
                    >
                      <template v-slot:prepend>
                        <q-icon name="img:pad/login/user.png" />
                      </template>
                      <template v-if="data.user_name" v-slot:append>
                        <q-icon
                          name="cancel"
                          @click.stop="data.user_name = null"
                          class="cursor-pointer"
                        />
                      </template>
                    </q-input>
                  </q-item-section>
                </q-item>

                <q-item>
                  <q-item-section>
                    <q-input
                      ref="password_input"
                      :loading="data.loading"
                      :disable="data.loading"
                      :type="data.show_password ? '' : 'password'"
                      v-model="data.password"
                      :placeholder="$t('please input password')"
                      lazy-rules
                      input-class="text-accent text-h6"
                      color="accent"
                      :dark="landspace"
                      :rules="[
                        (val) =>
                          (val && val.length > 0) ||
                          $t('Please type something'),
                      ]"
                      @keydown="
                        (evt) => {
                          if (evt.keyCode == 13) {
                            $refs?.login_button?.click();
                          }
                        }
                      "
                    >
                      <template v-slot:prepend>
                        <q-icon name="img:pad/login/password.png" />
                      </template>
                      <template v-if="data.password" v-slot:append>
                        <q-icon
                          v-if="show_show_password"
                          :name="
                            data.show_password ? 'visibility' : 'visibility_off'
                          "
                          class="cursor-pointer"
                          @click="data.show_password = !data.show_password"
                        />
                        <q-icon
                          name="cancel"
                          @click.stop="data.password = null"
                          class="cursor-pointer"
                        />
                      </template>
                    </q-input>
                  </q-item-section>
                </q-item>
                <q-item class="q-mt-sm">
                  <q-item-section>
                    <q-checkbox
                      :label="$t('remember password')"
                      v-model="remember_password"
                      color="accent"
                      class="text-accent"
                      :dark="landspace"
                      :disable="data.loading"
                    />
                  </q-item-section>
                  <q-item-section>
                    <q-checkbox
                      :label="$t('auto login')"
                      v-model="auto_login"
                      @update:model-value="remember_password = true"
                      color="accent"
                      class="text-accent"
                      :dark="landspace"
                      :disable="data.loading"
                    />
                  </q-item-section>
                  <q-item-section v-if="!$q.platform.is.capacitor">
                    <q-checkbox
                      :label="$t('full screen')"
                      v-model="full_screen"
                      @update:model-value="toogleFullScreen"
                      color="accent"
                      class="text-accent"
                      :dark="landspace"
                      :disable="data.loading"
                    />
                  </q-item-section>
                </q-item>
              </q-list>
            </q-form>
          </q-card-section>
          <q-card-actions align="center">
            <q-btn
              ref="login_button"
              class="text-h5"
              style="width: 60%"
              color="accent"
              no-caps
              :loading="data.loading"
              :label="$t('login')"
              rounded
              text-color="white"
              @click="$refs?.login_form?.submit()"
            />
          </q-card-actions>
        </q-card>
      </q-page>
    </q-page-container>
  </q-layout>

  <q-dialog
    ref="search_dialog"
    persistent
    v-model="show_search_dialog"
    @before-hide="searched_device_list = []"
    @show="searchDevice"
    @keydown="
      (evt) => {
        if (!loading && evt.keyCode == 27) {
          show_search_dialog = false;
        }
      }
    "
  >
    <q-card
      class="overflow-hidden"
      style="overflow-y: scroll; max-height: 60vh; max-width: 40vw"
    >
      <q-form @submit="onSubmit">
        <q-card-section class="q-ma-none q-pa-sm">
          <div class="row">
            <div class="col-auto text-h6">
              {{ $t("device list") }}
            </div>
            <q-space />
            <div>
              <q-btn
                :loading="data.loading"
                flat
                round
                icon="close"
                color="red"
                :disable="data.loading"
                v-close-popup
              >
                <q-tooltip>
                  {{ $t("close") }}
                </q-tooltip>
              </q-btn>
            </div>
          </div>
        </q-card-section>

        <q-separator />

        <q-card-section style="max-height: 55vh; width: 40vw" class="scroll">
          <q-scroll-area style="height: 36vh">
            <q-list>
              <q-item
                clickable
                v-for="(item, index) of searched_device_list"
                :key="index"
                @click="
                  () => {
                    data.ip_address = item;
                    show_search_dialog = false;
                  }
                "
              >
                {{ item }}
              </q-item>
            </q-list>
          </q-scroll-area>
        </q-card-section>

        <q-separator />

        <q-card-actions align="right">
          <q-btn
            :loading="data.loading"
            flat
            :label="$t('Close')"
            no-caps
            color="primary"
            v-close-popup
          />

          <q-btn
            flat
            :label="$t('search')"
            no-caps
            :loading="data.loading"
            color="primary"
            @click="searchDevice"
          />
        </q-card-actions>
      </q-form>
    </q-card>
  </q-dialog>
</template>

<script lang="ts">
import {
  defineComponent,
  onMounted,
  reactive,
  ref,
  Ref,
  computed,
  watch,
} from "vue";

import GlobalData from "src/common/GlobalData";
import { Cookies, LocalStorage, SessionStorage, useQuasar } from "quasar";
import ClientConnection from "src/common/ClientConnection";
import PermissionLevel from "src/entities/PermissionLevel";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { useStore } from "src/store";
import { Md5 } from "ts-md5";
import Initializer from "src/common/Initializer";
import { api } from "src/boot/axios";
import { HttpProtocol } from "src/entities/HttpProtocol";
import { Plugins as CapacitorPlugins } from "@capacitor/core";
import ValidationUtil from "src/common/ValidationUtil";

class _Data {
  user_name: string | null = null;
  password: string | null = null;
  loading = false;
  ip_address = window.location.hostname;
  show_password = false;

  constructor() {
    let temp = LocalStorage.getItem("default_ip_address");
    if (temp) {
      this.ip_address = temp.toString();
    } else {
      this.ip_address = window.location.hostname;
    }

    temp = LocalStorage.getItem("default_user_name");
    if (temp) {
      this.user_name = temp.toString();
    }

    temp = LocalStorage.getItem("default_password");
    if (temp) {
      this.password = temp.toString();
    }
  }
}

export default defineComponent({
  name: "PadPageLogin",

  components: {},

  setup() {
    const $q = useQuasar();
    const $t = useI18n();
    const $route = useRouter();
    const $store = useStore();
    const data = reactive(new _Data());

    const ____temp = $q.fullscreen.isActive;
    const full_screen = computed(() => $q.fullscreen.isActive);

    try {
      (window as any).setPadTheme();
    } catch {}

    const login_form: Ref<any> = ref(null);

    const remember_password = ref(false);
    const auto_login = ref(false);
    const show_show_password = ref(true);

    const show_search_dialog = ref(false);
    const searched_device_list: Ref<string[]> = ref([]);

    let cache_password: string | null = null;

    let web_socket: ClientConnection | null = null;
    let is_pwa = ["fullscreen", "standalone", "minimal-ui"].some(
      (displayMode) =>
        window.matchMedia("(display-mode: " + displayMode + ")").matches
    );

    const landspace = computed({
      get: () => $store.state.landspace,
      set: (val) => null,
    });

    $store.commit("updateLandspace", window.innerWidth > window.innerHeight);
    EventBus.getInstance().on(EventNamesDefine.WindowResize, () => {
      $store.commit("updateLandspace", window.innerWidth > window.innerHeight);
    });

    onMounted(() => {
      if (auto_login.value) {
        login_form.value.submit();
      }
    });

    try {
      remember_password.value = JSON.parse(
        Cookies.get("remember_password")
      ) as boolean;
      auto_login.value = JSON.parse(Cookies.get("auto_login")) as boolean;
      if (
        typeof remember_password.value == "undefined" ||
        remember_password.value == null
      ) {
        remember_password.value = false;
      }

      if (typeof auto_login.value == "undefined" || auto_login.value == null) {
        auto_login.value = false;
      }

      if (remember_password.value) {
        data.user_name = Cookies.get("user_name") ?? data.user_name;
        cache_password = Cookies.get("password");
        if (
          typeof cache_password != "undefined" &&
          cache_password != null &&
          cache_password.length == 32
        ) {
          data.password = cache_password;
        } else {
          cache_password = null;
        }
      }
    } catch {}

    watch(
      () => data.password,
      () => {
        show_show_password.value = true;
      }
    );

    show_show_password.value = data.password != cache_password;

    return {
      login_form,
      data,
      remember_password,
      auto_login,
      landspace,
      is_pwa,
      show_show_password,
      full_screen,
      show_search_dialog,
      searched_device_list,

      async onSubmit() {
        data.loading = true;
        return new Promise((resolve) => {
          try {
            let global_data = GlobalData.getInstance();
            api
              .get(HttpProtocol.RequestPathGetWebscoketPort)
              .then((response) => {
                let final_ws_port = GlobalData.kDefaultWebsocektPort;
                if (response && typeof response.data != "undefined") {
                  if (typeof response.data != "number") {
                    const temp_port = parseInt(response.data);
                    if (!isNaN(temp_port) && temp_port != Infinity) {
                      final_ws_port = temp_port;
                    }
                  } else {
                    final_ws_port = response.data;
                  }
                  const url =
                    "ws://" +
                    data.ip_address +
                    ":" +
                    final_ws_port.toString() +
                    GlobalData.kWebsocketResource;
                  web_socket = new ClientConnection(
                    url,
                    data.user_name,
                    data.password == cache_password
                      ? data.password
                      : Md5.hashStr(data.password ?? "admin")
                  );
                  let timer = setTimeout(() => {
                    web_socket?.destory();
                    web_socket = null;
                    $q.notify({
                      color: "negative",
                      icon: "warning",
                      message:
                        $t.t("login fail!") +
                        $t.t("connect time out!") +
                        $t.t(
                          "please check server state, or check server ip address!"
                        ),
                      position: "center",
                      timeout: 1500,
                    });
                    SessionStorage.set("auth", PermissionLevel.None);
                    resolve(false);
                    data.loading = false;
                  }, 5000);
                  web_socket.login_callback = (is_login) => {
                    clearTimeout(timer);
                    if (is_login && web_socket) {
                      global_data.addClient(data.ip_address, web_socket);
                      global_data.setCurrentClientName(data.ip_address);

                      SessionStorage.set("auth", PermissionLevel.Root);
                      SessionStorage.set("url", url);
                      SessionStorage.set("name", data.ip_address);
                      SessionStorage.set("user_name", data.user_name);
                      SessionStorage.set(
                        "password",
                        data.password == cache_password
                          ? data.password
                          : Md5.hashStr(data.password ?? "admin")
                      );

                      // TODO add self to setConnects

                      if (remember_password.value) {
                        Cookies.set("remember_password", JSON.stringify(true), {
                          expires: 15,
                        });
                        Cookies.set(
                          "auto_login",
                          JSON.stringify(auto_login.value),
                          {
                            expires: 15,
                          }
                        );
                        Cookies.set("user_name", data.user_name ?? "admin", {
                          expires: 15,
                        });
                        Cookies.set(
                          "password",
                          data.password == cache_password
                            ? data.password ?? Md5.hashStr("admin")
                            : Md5.hashStr(data.password ?? "admin"),
                          {
                            expires: 15,
                          }
                        );
                      } else {
                        Cookies.remove("remember_password");
                        Cookies.remove("auto_login");
                        Cookies.remove("name");
                        Cookies.remove("user_name");
                        Cookies.remove("password");
                      }

                      $store.commit("setDeviceIpAddress", data.ip_address);

                      setTimeout(() => {
                        new Initializer({
                          $t,
                          $store,
                          $q,
                        })
                          .initialize()
                          .then(() => {
                            $store.commit("setInitialized");
                          });
                      }, 0);

                      $route.push("/");
                    } else {
                      $q.notify({
                        color: "negative",
                        icon: "warning",
                        message:
                          $t.t("login fail!") + $t.t("user or password error!"),
                        position: "center",
                        timeout: 1500,
                      });
                      SessionStorage.set("auth", PermissionLevel.None);
                    }
                    resolve(true);
                    data.loading = false;
                  };
                }
              })
              .catch(() => {
                resolve(true);
                data.loading = false;
              });
          } catch {
            resolve(true);
            data.loading = false;
          }
        });
      },
      onReset() {
        data.user_name = null;
        data.password = null;
        remember_password.value = false;
      },
      toogleFullScreen() {
        if (!$q.fullscreen.isCapable) {
          if ($q.platform.is.ipad) {
            $q.notify({
              type: "warning",
              message:
                $t.t("on the iPad, only Safari supports full screen") + "!",
              position: "top",
              timeout: 1500,
            });
          } else {
            $q.notify({
              type: "warning",
              message:
                $t.t("the current browser does not support full screen") + "!",
              position: "top",
              timeout: 1500,
            });
          }

          return;
        }
        if ($q.fullscreen.isActive) {
          $q.fullscreen.exit();
        } else {
          $q.fullscreen.request().catch((e: any) => {
            console.log(e);
          });
        }
      },
      searchDevice() {
        if ($q.platform.is.capacitor) {
          data.loading = true;
          searched_device_list.value = [];
          try {
            const { SearchDevicePlugin } = CapacitorPlugins;
            interface SearchDeviceResult {
              ip_list: any;
            }
            SearchDevicePlugin.searchDevice()
              .then((result: SearchDeviceResult) => {
                if (result && result.ip_list) {
                  try {
                    searched_device_list.value = JSON.parse(result.ip_list);
                  } catch (e) {
                    console.log(e);
                  }
                }
                data.loading = false;
              })
              .final(() => {
                data.loading = false;
              });
          } catch (e) {
            console.log(e);
          }
        }
      },
      isHost(str: string) {
        return ValidationUtil.isHost(str);
      },
    };
  },
});
</script>
