import { acceptHMRUpdate, defineStore } from "pinia";
import { API } from "./api";
import type { Loading } from "./helpers";
import type { Credentials, DoorSaved, ImageData, SiteConfigModel } from "./model";
import { Door } from "./rects/door";

declare global {
  interface Navigator {
    readonly msMaxTouchPoints: number;
  }
}

type State = {
  on_initialized: (() => void)[] | null;
  is_touch_device: boolean;
  is_admin: boolean;
  site_config: SiteConfigModel;
  background_image: Loading<ImageData>;
  user_doors: Door[];
  next_door_target: number | null;
};

export const advent22Store = defineStore("advent22", {
  state: (): State => ({
    on_initialized: [],
    is_touch_device:
      window.matchMedia("(any-hover: none)").matches ||
      "ontouchstart" in window ||
      navigator.maxTouchPoints > 0 ||
      navigator.msMaxTouchPoints > 0,
    is_admin: false,
    site_config: {
      title: document.title,
      subtitle: "",
      content: "",
      footer: "",
    },
    background_image: "loading",
    user_doors: [],
    next_door_target: null,
  }),

  actions: {
    async init(): Promise<void> {
      await this.update();

      if (this.on_initialized !== null) {
        for (const callback of this.on_initialized) callback();
      }
      this.on_initialized = null;
    },

    async update(): Promise<void> {
      try {
        const favicon = await API.request<ImageData>("user/favicon");

        const link: HTMLLinkElement =
          document.querySelector("link[rel*='icon']") ??
          document.createElement("link");
        link.rel = "shortcut icon";
        link.type = "image/x-icon";
        link.href = favicon.data_url;

        if (link.parentElement === null)
          document.getElementsByTagName("head")[0]!.appendChild(link);
      } catch { }

      try {
        const [is_admin, site_config, background_image, user_doors, next_door] =
          await Promise.all([
            this.update_is_admin(),
            API.request<SiteConfigModel>("user/site_config"),
            API.request<ImageData>("user/background_image"),
            API.request<DoorSaved[]>("user/doors"),
            API.request<number | null>("user/next_door"),
          ]);
        void is_admin; // discard value

        document.title = site_config.title;

        if (site_config.subtitle !== "")
          document.title += " – " + site_config.subtitle;

        this.site_config = site_config;
        this.background_image = background_image;

        this.user_doors.length = 0;
        for (const door_saved of user_doors) {
          this.user_doors.push(Door.load(door_saved));
        }

        if (next_door !== null) this.next_door_target = Date.now() + next_door;
      } catch {
        this.background_image = "error";
      }
    },

    when_initialized(callback: () => void): void {
      if (this.on_initialized === null) {
        callback();
      } else {
        this.on_initialized.push(callback);
      }
    },

    async update_is_admin(): Promise<boolean> {
      this.is_admin = await API.request<boolean>("admin/is_admin");
      return this.is_admin;
    },

    async login(creds: Credentials): Promise<boolean> {
      API.creds = creds;
      return await this.update_is_admin();
    },

    logout() {
      API.creds = null;
      this.is_admin = false;
    },

    toggle_touch_device(): void {
      this.is_touch_device = !this.is_touch_device;
    },
  },
});

if (import.meta.webpackHot) {
  import.meta.webpackHot.accept(
    acceptHMRUpdate(advent22Store, import.meta.webpackHot),
  );
}
