import { kemonoAPI } from "@wp/api";
import { addFavouritePost, findFavouritePost, removeFavouritePost } from "@wp/js/favorites";
import { LoadingIcon, registerMessage, showTooltip } from "@wp/components";
import { createComponent } from "@wp/js/component-factory";
import { isLoggedIn } from "@wp/js/account";
import MicroModal from "micromodal";
import { diffChars } from "diff";

import "fluid-player/src/css/fluidplayer.css";
import fluidPlayer from "fluid-player";

const meta = {
  service: null,
  user: null,
  postID: null,
};

/**
 * @param {HTMLElement} section
 */
export async function postPage(section) {
  /**
   * @type {HTMLElement}
   */
  const buttonPanel = section.querySelector(".post__actions");

  meta.service = document.head.querySelector("[name='service']").content;
  meta.user = document.head.querySelector("[name='user']").content;
  meta.postID = document.head.querySelector("[name='id']").content;
  const postBody = section.querySelector(".post__body");

  section.addEventListener("click", Expander);

  cleanupBody(postBody);
  await initButtons(buttonPanel);
  addRevisionHandler();

  document.addEventListener("DOMContentLoaded", (d, ev) => {addShowTagsButton()});
  window.addEventListener("resize",  (d, ev) => {addShowTagsButton()});

  MicroModal.init();
  // diffComments();

  Array.from(document.getElementsByTagName("video")).forEach((_, i) => {
    fluidPlayer(`kemono-player${i}`, {
      layoutControls: {
        fillToContainer: false,
        preload: "none",
      },
      vastOptions: {
        adList: window.videoAds,
        adTextPosition: "top left",
        maxAllowedVastTagRedirects: 2,
        vastAdvanced: {
          vastLoadedCallback: function () {},
          noVastVideoCallback: function () {},
          vastVideoSkippedCallback: function () {},
          vastVideoEndedCallback: function () {},
        },
      },
    });
  });
}

/**
 * Apply some fixes to the content of the post.
 * @param {HTMLElement} postBody
 */
function cleanupBody(postBody) {
  const postContent = postBody.querySelector(".post__content");
  const isNoPostContent = !postContent || (!postContent.childElementCount && !postContent.childNodes.length);

  // content is empty
  if (isNoPostContent) {
    return;
  }

  // pixiv post
  if (meta.service === "fanbox") {
    // its contents is a text node
    if (!postContent.childElementCount && postContent.childNodes.length === 1) {
      // wrap the text node into `<pre>`
      const [textNode] = Array.from(postContent.childNodes);
      const pre = document.createElement("pre");
      textNode.after(pre);
      pre.appendChild(textNode);
    }

    // remove paragraphs with only `<br>` in them
    const paragraphs = postContent.querySelectorAll("p");
    paragraphs.forEach((para) => {
      if (para.childElementCount === 1 && para.firstElementChild.tagName === "BR") {
        para.remove();
      }
    });
  }

  Array.from(document.links).forEach((anchour) => {
    // remove links to fanbox from the post
    const hostname = anchour.hostname;
    if (hostname.includes("downloads.fanbox.cc")) {
      if (anchour.classList.contains("image-link")) {
        anchour.remove();
      } else {
        let el = document.createElement("span");
        el.textContent = anchour.textContent;
        anchour.replaceWith(el);
      }
    }
    else if (hostname.includes("fanbox.cc")){
      anchour.href = anchour.href.replace(/https?:\/\/(?:[a-zA-Z0-9-]*.)?fanbox\.cc\/(?:(?:manage\/)|(?:@[a-zA-Z\d]+\/)|)posts\/(\d+)/g, '/fanbox/post/$1');
    }
    else if (hostname.includes("patreon.com")){
      anchour.href = anchour.href.replace( /https?:\/\/(?:[\w-]*.)?patreon\.com\/posts\/.*\b(\d+)\b(?:\?.*)?/g, '/patreon/post/$1');
    }
  });

  // Remove needless spaces and empty paragraphs.
  /**
   * @type {NodeListOf<HTMLParagraphElement}
   */
  const paragraphs = postContent.querySelectorAll("p:empty");
  Array.from(paragraphs).forEach((paragraph) => {
    if (paragraph.nextElementSibling && paragraph.nextElementSibling.tagName === "BR") {
      paragraph.nextElementSibling.remove();
      paragraph.remove();
    } else {
      paragraph.remove();
    }
  });
}

/**
 * @param {HTMLElement} buttonPanel
 */
async function initButtons(buttonPanel) {
  /**
   * @type {HTMLButtonElement}
   */
  const flagButton = buttonPanel.querySelector(".post__flag");
  /**
   * @type {HTMLButtonElement}
   */
  const favButton = createComponent("post__fav");
  const isFavorited = isLoggedIn && (await findFavouritePost(meta.service, meta.user, meta.postID));

  if (isFavorited) {
    const [icon, text] = favButton.children;
    favButton.classList.add("post__fav--unfav");
    icon.textContent = "★";
    text.textContent = "Unfavorite";
  }

  if (!flagButton.classList.contains("post__flag--flagged")) {
    flagButton.addEventListener("click", handleFlagging(meta.service, meta.user, meta.postID));
  }

  favButton.addEventListener("click", handleFavouriting(meta.service, meta.user, meta.postID));

  buttonPanel.appendChild(favButton);

  document.addEventListener("keydown", (e) => {
    switch (e.key) {
      case "ArrowLeft":
        document.querySelector(".post__nav-link.prev")?.click();
        break;
      case "ArrowRight":
        document.querySelector(".post__nav-link.next")?.click();
        break;
    }
  });
}

function addRevisionHandler() {
  let selector = document.getElementById("post-revision-selection");
  if (selector) {
    selector.addEventListener("change", (ev) => {
      let revision = ev.target.selectedOptions[0].value;
      if (revision)
        location.pathname = `/${meta.service}/user/${meta.user}/post/${meta.postID}/revision/${revision}`;
      else
        location.pathname = `/${meta.service}/user/${meta.user}/post/${meta.postID}`;
    });
  }
}

/**
 * @param {string} service
 * @param {string} user
 * @param {string} postID
 * @returns {(event: MouseEvent) => Promise<void>}
 */
function handleFlagging(service, user, postID) {
  return async (event) => {
    /**
     * @type {HTMLButtonElement}
     */
    const button = event.target;
    const [icon, text] = button.children;
    const loadingIcon = LoadingIcon();
    const isConfirmed = confirm(
      "Are you sure you want to flag this post for reimport? Only do this if data in the post is broken/corrupted/incomplete.\nThis is not a deletion button.",
    );

    button.classList.add("post__flag--loading");
    button.disabled = true;
    button.insertBefore(loadingIcon, text);

    try {
      if (isConfirmed) {
        const isFlagged = await kemonoAPI.posts.attemptFlag(service, user, postID);

        if (isFlagged) {
          const parent = button.parentElement;
          const newButton = createComponent("post__flag post__flag--flagged");

          parent.insertBefore(newButton, button);
          button.remove();
        }
      }
    } catch (error) {
      console.error(error);
    } finally {
      loadingIcon.remove();
      button.disabled = false;
      button.classList.remove("post__flag--loading");
    }
  };
}

/**
 * @param {string} service
 * @param {string} user
 * @param {string} postID
 * @returns {(event: MouseEvent) => Promise<void>}
 */
function handleFavouriting(service, user, postID) {
  return async (event) => {
    /**
     * @type {HTMLButtonElement}
     */
    const button = event.currentTarget;
    const isLoggedIn = localStorage.getItem("logged_in") === "yes";

    if (!isLoggedIn) {
      showTooltip(button, registerMessage(null, "Favoriting"));
      return;
    }

    const [icon, text] = button.children;
    const loadingIcon = LoadingIcon();

    button.disabled = true;
    button.classList.add("post__fav--loading");
    button.insertBefore(loadingIcon, text);

    try {
      if (button.classList.contains("post__fav--unfav")) {
        const isUnfavorited = await removeFavouritePost(service, user, postID);

        if (isUnfavorited) {
          button.classList.remove("post__fav--unfav");
          icon.textContent = "☆";
          text.textContent = "Favorite";
        }
      } else {
        const isFavorited = await addFavouritePost(service, user, postID);

        if (isFavorited) {
          button.classList.add("post__fav--unfav");
          icon.textContent = "★";
          text.textContent = "Unfavorite";
        }
      }
    } catch (error) {
      console.error(error);
    } finally {
      loadingIcon.remove();
      button.disabled = false;
      button.classList.remove("post__fav--loading");
    }
  };
}

// expander.js
function Expand(c, t) {
  if (!c.naturalWidth) {
    return setTimeout(Expand, 10, c, t);
  }
  c.style.maxWidth = "100%";
  c.style.display = "";
  t.style.display = "none";
  t.style.opacity = "";
}

/**
 * @param {MouseEvent} e
 */
function Expander(e) {
  /**
   * @type {HTMLElement}
   */
  var t = e.target;
  if (t.parentNode.classList.contains("fileThumb")) {
    e.preventDefault();
    if (t.hasAttribute("data-src")) {
      var c = document.createElement("img");
      c.setAttribute("src", t.parentNode.getAttribute("href"));
      c.style.display = "none";
      t.parentNode.insertBefore(c, t.nextElementSibling);
      t.style.opacity = "0.75";
      setTimeout(Expand, 10, c, t);
    } else {
      var a = t.parentNode;
      a.firstChild.style.display = "";
      a.removeChild(t);
      a.offsetTop < window.pageYOffset && a.scrollIntoView({ top: 0, behavior: "smooth" });
    }
  }
}

function addShowTagsButton() {
  let div = document.querySelector("#post-tags > div");
  if (document.getElementById("show-tag-overflow-button")){
    document.getElementById("show-tag-overflow-button").remove();
  }
  if (div && div.offsetWidth < div.scrollWidth) {
    // tags overflow
    let button = document.createElement("a");
    button.href = "javascript:void 0";
    button.id = "show-tag-overflow-button";
    button.textContent = "Show all »";
    button.onclick = (e) => {
      if (div.classList.contains("show-overflow")) {
        div.classList.remove("show-overflow");
        button.textContent = "Show all»";
      } else {
        div.classList.add("show-overflow");
        button.textContent = "« Hide";
      }
    }
    div.parentElement.appendChild(button);
  }
}

function* pairwise(iterable) {
  const iterator = iterable[Symbol.iterator]();
  let a = iterator.next();
  if (a.done) return;
  let b = iterator.next();
  while (!b.done) {
    yield [a.value, b.value];
    a = b;
    b = iterator.next();
  }
}

function diffComments() {
  let comments = Array.from(document.querySelectorAll(".comment-revisions-dialog .prose"));
  let pairs = pairwise(comments);
  for (let [old, new_] of pairs) {
    let newSpan = document.createElement("span");
    newSpan.classList.add("prose");
    diffChars(old.textContent, new_.textContent)
      .forEach(c => {
        let span = document.createElement("span");
        if (c.added) { span.classList.add("added"); }
        else if (c.removed) { span.classList.add("removed"); }
        span.appendChild(document.createTextNode(c.value));
        newSpan.appendChild(span);
      });

    old.replaceWith(newSpan);
  }
}
