/*
Copyright 2022 0xf8

This file is part of Galerie

Galerie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Galerie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Galerie. If not, see <https://www.gnu.org/licenses/>.
*/

import App from "./app";
import React from "react";

import jQuery from "jquery";
const $ = jQuery;

import Settings, { apiUrl } from "./settings";

const settings = new Settings();

let global_ActiveContextMenu: ContextMenu = null;
let global_ActivePopout: Popout = null;


// ===================
// === ContextMenu ===
// ===================

class ContextMenu {
  public menu: JQuery<HTMLElement>;
  private overlay: JQuery<HTMLElement>;

  constructor(label: string, buttons: JQuery<HTMLElement>[], position: [any, any]) {
    this.overlay = $("<div class='overlay'>");
    this.menu = $("<div class='contextmenu'>");

    let labelElement = $("<span>");
    labelElement.text(label);
    this.menu.append(labelElement);

    for (let _b in buttons) this.menu.append(buttons[_b]);

    this.menu.css("top", position[1]);
    this.menu.css("left", position[0]);

    this.overlay.append(this.menu);
  }

  public static async createButton(text: string) {
    return $("<button class='option'>").text(text);
  }

  public async create(): Promise<boolean> {
    if (global_ActiveContextMenu != null)
      return false;
    global_ActiveContextMenu = this;

    $("div#container").append(this.overlay);

    $(document).one("click", async (ev) => {
      ev.preventDefault();

      await this.destroy();
    })

    return true;
  }

  public async destroy(): Promise<boolean> {
    if (global_ActiveContextMenu != this)
      return false;
    global_ActiveContextMenu = null;

    this.overlay.remove();
    this.menu.remove();
  }
}


class Popout {
  private element: JQuery<HTMLElement>;
  private overlay: JQuery<HTMLElement>;

  constructor(element: JQuery<HTMLElement>, src: string) {
    this.element = element.clone();

    this.element.removeClass("resourceh resource");
    this.element.addClass("popout");

    this.overlay = $("<div class='overlay'>")
    this.overlay.append(this.element);

    this.element.on("contextmenu", Popout.createPopoutMenu(this.element, src));
  }

  create() {
    if (global_ActivePopout != null)
      return;
    global_ActivePopout = this;

    $("div#container").append(this.overlay);
    this.overlay.one("click", (event) => {
      event.preventDefault();

      this.destroy();
    })

  }

  destroy() {
    if (global_ActivePopout != this)
      return;
    global_ActivePopout = null;

    this.overlay.remove();
    this.element.remove();
  }

  static createPopoutMenu(element: JQuery<HTMLElement>, src: string) {
    return async (event) => {
      event.preventDefault();
  
      let favoriteButton = await ContextMenu.createButton("Add to favorites");
      let blacklistButton = await ContextMenu.createButton("Add to blacklist");
  
      let removeFButton = await ContextMenu.createButton("Remove from favorites");
      let removeBButton = await ContextMenu.createButton("Remove from blacklist");
  
      let undoLFButton = await ContextMenu.createButton("Undo last favorite");
      let undoLBButton = await ContextMenu.createButton("Undo last blacklist");
  
      let clearFButton = await ContextMenu.createButton("Clear favorites");
      let clearBButton = await ContextMenu.createButton("Clear blacklist");
  
      let reloadButton = await ContextMenu.createButton("Reload images");
      let reloadOFButton = await ContextMenu.createButton("Reload and show only favorites");
  
      let closeMenuButton = await ContextMenu.createButton("Close this menu");
  
      let Menu = new ContextMenu("Manage resource", [
        favoriteButton, blacklistButton, $("<hr/>"),
        removeFButton, removeBButton, $("<hr/>"),
        undoLFButton, undoLBButton, $("<hr/>"),
        clearFButton, clearBButton, $("<hr/>"),
        reloadButton, reloadOFButton, closeMenuButton
      ], [event.clientX, event.clientY]);
  
      favoriteButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.favorites.push(src);
      });
      blacklistButton.on("click", async (ev) => {
        ev.preventDefault();
        element.remove();
        await settings.blacklist.push(src);
      });
  
      removeFButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.favorites.delete(src);
      })
      removeBButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.blacklist.delete(src);
      })
  
      undoLFButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.favorites.pop();
      });
      undoLBButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.blacklist.pop();
      });
  
      clearFButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.favorites.clear();
      });
      clearBButton.on("click", async (ev) => {
        ev.preventDefault();
        await settings.blacklist.clear();
      })
  
      reloadButton.on("click", async (ev) => {
        ev.preventDefault();
  
        await Gallery.loadDisplay(await settings.cache.shuffle());
      })
      reloadOFButton.on("click", async (ev) => {
        ev.preventDefault();
  
        await Gallery.loadDisplay(await settings.favorites.shuffle());
      })
  
      closeMenuButton.on("click", async (ev) => {
        ev.preventDefault();
  
        await Menu.destroy();
      })
  
      Menu.create();
    }
  }
}

let _log = (f, ...m: any) => {
  f(...m);
}

let log = (...m: any[]) => {
  _log(console.log, ...m);
}

let warn = (...m: any[]) => {
  _log(console.warn, ...m);
}

let error = (...m: any[]) => {
  _log(console.error, ...m);
}

let debug = (...m: any[]) => {
  _log(console.debug, ...m);
}

// ===============
// === Gallery ===
// ===============

class gallery {
  constructor() {}

  public async load(): Promise<void> {
    log("Validating cache");
    
    await settings.cache.load();
  }

  public async loadDisplay(data: string[]): Promise<void> {
    await this.clearDisplay();

    if (data.length != 0) 
      for (let i = 0; i < data.length; i++) {
        let f = await data.at(i);

        if (await settings.blacklist.contains(f))
          continue;

        this.createElement("img", f).then((e) => e.appendTo($("div#display")))
      }
    else {
      let t = $("<span style='margin-top: 3em'>There's nothing here. <a style='color: white; text-decoration: none' href='#'>Reload?</a></span>");
      t.children("a").on("click", async (e) => {
        e.preventDefault();
        this.loadDisplay(await settings.cache.shuffle());
      });
      // let t = <span>There's nothing here. <a href="#" onClick={ async () => this.loadDisplay(await settings.cache.shuffle()) }>Reload?</a></span>
      $(t).appendTo($("div#display"))
    }
  }

  private async clearDisplay(): Promise<void> {
    $("#display").children().remove();
  }

  private async createElement(tag: string, src: string): Promise<JQuery<HTMLElement>> {
    let element = $(`<${tag} class='resource resourceh'>`);
    element.prop("loop", true);
    element.prop("nocontrols", true);
    element.attr("src", `${apiUrl}img/${src}`);

    let popoutHandler = async (event) => {
      event.preventDefault();

      const popout = new Popout(element, src);

      popout.create();
    }

    element.on("click", popoutHandler);

    element.on("contextmenu", Popout.createPopoutMenu(element, src));

    return element;
  }
};


let Gallery = new gallery();

window.onload = async () => {
  await Gallery.load();
  await Gallery.loadDisplay(await settings.cache.shuffle());
}

const root = App(() => {
  return <>
    <div id="container">
      <div id="display"></div>
    </div>
  </>;
})