<template>
  <router-view />

  <!-- https://github.com/emmanuelsw/notiwind -->
  <NotificationGroup group="alert">
    <div
      class="fixed top-4 right-4 w-full max-w-sm flex flex-col items-start justify-end"
    >
      <Notification
        v-slot="{ notifications, close }"
        enter="transform ease-out duration-300 transition"
        enter-from="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-4"
        enter-to="translate-y-0 opacity-100 sm:translate-x-0"
        leave="transition ease-in duration-500"
        leave-from="opacity-100"
        leave-to="opacity-0"
        move="transition duration-500"
        move-delay="delay-300"
      >
        <div
          v-for="notification in notifications"
          :key="notification.id"
          class="w-full"
          role="alert"
        >
          <div
            v-if="notification.type === 'toast'"
            class="w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-900/90 text-white rounded-lg shadow-md"
          >
            <div class="w-full px-4 py-3">
              <span class="font-semibold">{{ notification.title }}</span>
              <p class="text-sm">{{ notification.text }}</p>
            </div>
          </div>

          <div
            v-if="notification.type === 'info'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-slate-600 text-slate-100"
            >
              <fa icon="circle-info" class="fa-fw fa-xl"></fa>
            </div>

            <div class="relative w-full pl-4 pr-8 py-2 text-slate-900">
              <span class="font-semibold">{{ notification.title }}</span>
              <p class="text-sm">{{ notification.text }}</p>

              <button
                @click="close(notification.id)"
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-slate-200 text-slate-600"
              >
                <fa icon="xmark" class="fa-fw"></fa>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'success'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-emerald-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-emerald-600 text-emerald-100"
            >
              <fa icon="circle-info" class="fa-fw fa-xl"></fa>
            </div>

            <div class="relative w-full pl-4 pr-8 py-2 text-emerald-900">
              <span class="font-semibold">{{ notification.title }}</span>
              <p class="text-sm">{{ notification.text }}</p>

              <button
                @click="close(notification.id)"
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-emerald-200 text-emerald-600"
              >
                <fa icon="xmark" class="fa-fw"></fa>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'warning'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-amber-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-amber-600 text-amber-100"
            >
              <fa icon="triangle-exclamation" class="fa-fw fa-xl"></fa>
            </div>

            <div class="relative w-full pl-4 pr-8 py-2 text-amber-900">
              <span class="font-semibold">{{ notification.title }}</span>
              <p class="text-sm">{{ notification.text }}</p>

              <button
                @click="close(notification.id)"
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-amber-200 text-amber-600"
              >
                <fa icon="xmark" class="fa-fw"></fa>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'danger'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-rose-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-rose-600 text-rose-100"
            >
              <fa icon="triangle-exclamation" class="fa-fw fa-xl"></fa>
            </div>

            <div class="relative w-full pl-4 pr-8 py-2 text-rose-900">
              <span class="font-semibold">{{ notification.title }}</span>
              <p class="text-sm">{{ notification.text }}</p>

              <button
                @click="close(notification.id)"
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-rose-200 text-rose-600"
              >
                <fa icon="xmark" class="fa-fw"></fa>
              </button>
            </div>
          </div>
        </div>
      </Notification>
    </div>
  </NotificationGroup>

  <NotificationGroup group="modal">
    <div class="fixed z-[100] top-0 inset-x-0 w-full">
      <Notification
        v-slot="{ notifications, close }"
        enter="transform ease-out duration-300 transition"
        enter-from="translate-y-2 opacity-0 sm:translate-y-4"
        enter-to="translate-y-0 opacity-100 sm:translate-y-0"
        leave="transition ease-in duration-500"
        leave-from="opacity-100"
        leave-to="opacity-0"
        move="transition duration-500"
        move-delay="delay-300"
      >
        <div
          v-for="notification in notifications"
          :key="notification.id"
          class="w-full"
          role="alert"
        >
          <div
            v-if="notification.type === 'notification-permission'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <p class="text-lg mb-4">
                  Would you like to <b>turn on</b> notifications for this app?
                </p>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                  @click="
                    close(notification.id);
                    turnOnNotifications();
                  "
                >
                  Turn on Notifications
                </button>
                <div class="grid grid-cols-2 gap-2">
                  <button
                    @click="maybeLater(notification.id)"
                    class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
                  >
                    Maybe Later
                  </button>
                  <button
                    @click="never(notification.id)"
                    class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md"
                  >
                    Never
                  </button>
                </div>
              </div>
            </div>
          </div>
          <div
            v-if="notification.type === 'notification-mute'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <p class="text-lg mb-4">Mute app notifications:</p>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 1 Hour
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 8 Hours
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 24 Hours
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  Until I turn it back on
                </button>
                <button
                  @click="close(notification.id)"
                  class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
                >
                  Cancel
                </button>
              </div>
            </div>
          </div>
          <div
            v-if="notification.type === 'notification-off'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <p class="text-lg mb-4">
                  Would you like to <b>turn off</b> notifications for this app?
                </p>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  Turn Off Notifications
                </button>
                <button
                  @click="close(notification.id)"
                  class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
                >
                  Leave it On
                </button>
              </div>
            </div>
          </div>
        </div>
      </Notification>
    </div>
  </NotificationGroup>
</template>

<style></style>

<script lang="ts">
import { Vue, Component } from "vue-facing-decorator";
import axios from "axios";

import { AppString } from "@/constants/app";
import { db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";

interface Notification {
  group: string;
  type: string;
  title: string;
  text: string;
}

@Component
export default class App extends Vue {
  $notify!: (notification: Notification, timeout?: number) => void;

  b64 = "";

  async mounted() {
    try {
      await db.open();
      const settings = await db.settings.get(MASTER_SETTINGS_KEY);
      let pushUrl: string = AppString.DEFAULT_PUSH_SERVER;
      if (settings?.webPushServer) {
        pushUrl = settings.webPushServer;
      }

      await axios.get(pushUrl + "/web-push/vapid").then((response) => {
        this.b64 = response.data?.vapidKey;
        console.log("Got vapid key:", this.b64);
      });
      if (!this.b64) {
        this.$notify(
          {
            group: "alert",
            type: "danger",
            title: "Error Setting Notifications",
            text: "Could not set notifications.",
          },
          -1,
        );
      }
    } catch (error) {
      console.error("Got an error initializing notifications:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error Setting Notifications",
          text: "Got an error setting notifications.",
        },
        -1,
      );
    }
  }

  private askPermission(): Promise<NotificationPermission> {
    // Check if Notifications are supported
    if (!("Notification" in window)) {
      alert("This browser does not support notifications.");
      return Promise.reject("This browser does not support notifications.");
    }

    // Check existing permissions
    if (Notification.permission === "granted") {
      return Promise.resolve("granted");
    }

    // Request permission
    return new Promise((resolve, reject) => {
      const permissionResult = Notification.requestPermission((result) => {
        resolve(result);
      });

      if (permissionResult) {
        permissionResult.then(resolve, reject);
      }
    }).then((permissionResult) => {
      console.log("Permission result:", permissionResult);

      if (permissionResult !== "granted") {
        alert("We need notification permission to provide certain features.");
        return Promise.reject("We weren't granted permission.");
      }

      return permissionResult;
    });
  }

  async turnOnNotifications() {
    return this.askPermission()
      .then((permission) => {
        console.log("Permission granted:", permission);

        // Call the function and handle promises
        this.subscribeToPush()
          .then(() => {
            console.log("Subscribed successfully.");
            // Assuming the subscription object is available
            return navigator.serviceWorker.ready;
          })
          .then((registration) => {
            // Fetch the existing subscription object from the registration
            return registration.pushManager.getSubscription();
          })
          .then((subscription) => {
            if (subscription) {
              console.log(subscription);
              return this.sendSubscriptionToServer(subscription);
            } else {
              throw new Error("Subscription object is not available.");
            }
          })
          .then(() => {
            console.log("Subscription data sent to server.");
          })
          .catch((error) => {
            console.error(
              "Subscription or server communication failed:",
              error,
            );
          });
      })
      .catch((error) => {
        console.error("An error occurred:", error);
        // Handle error appropriately here
      });
  }

  // Function to convert URL base64 to Uint8Array
  private urlBase64ToUint8Array(base64String: string): Uint8Array {
    const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
    const base64 = (base64String + padding)
      .replace(/-/g, "+")
      .replace(/_/g, "/");
    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
      outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
  }

  // The subscribeToPush method
  private subscribeToPush(): Promise<void> {
    return new Promise<void>((resolve, reject) => {
      if ("serviceWorker" in navigator && "PushManager" in window) {
        const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
        const options: PushSubscriptionOptions = {
          userVisibleOnly: true,
          applicationServerKey: applicationServerKey,
        };
        console.log(options);

        navigator.serviceWorker.ready
          .then((registration) => {
            return registration.pushManager.subscribe(options);
          })
          .then((subscription) => {
            console.log("Push subscription successful:", subscription);
            resolve();
          })
          .catch((error) => {
            console.error("Push subscription failed:", error, options);
            reject(error);
          });
      } else {
        const errorMsg = "Push messaging is not supported";
        console.warn(errorMsg);
        reject(new Error(errorMsg));
      }
    });
  }

  private sendSubscriptionToServer(
    subscription: PushSubscription,
  ): Promise<void> {
    console.log(subscription);
    return fetch("/web-push/subscribe", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(subscription),
    }).then((response) => {
      if (!response.ok) {
        throw new Error("Failed to send subscription to server");
      }
      console.log("Subscription sent to server successfully.");
    });
  }

  never(ID: string) {
    alert(ID);
  }

  maybeLater(ID: string) {
    alert(ID);
  }
}
</script>
