// ==UserScript==
// @name         MLPFicReviews Extras
// @namespace    http://ponepaste.org/5555
// @version      0.2
// @description  Adds a few handy functions to mlpficreviews.org.uk
// @author       Fillyanon
// @match        http://www.mlpficreviews.org.uk/*
// @grant        none
// ==/UserScript==
const style = `
body {
  background-image: url("https://u.smutty.horse/mdqwfehyeeo.png");
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: 100%;
}
.page {
  width: 1100px;
  background: #eef2ff;
  padding: 0;
}
h1 {
  text-align: center;
  font-size: 2.5rem;
  padding: 1rem;
  background: hsl(60, 60%, 90%);
}
h1::before {
  content: url("https://static.fimfiction.net/images/logo-2x.png");
  display: block;
}
a {
  text-decoration: none;
}
h2 {
  margin-top: 1rem;
  text-align: center;
}
.sorter {
margin: 1rem auto;
display: block;
width: min-content;
}
.sorter button {
width: 100%;
height: 1.5rem;
}
ul {
position:relative;
  display: grid;
  grid-template-columns: repeat(3, calc(33% - 0.5rem));
  /*grid-auto-rows: 1fr; ̇*/
  grid-gap: 1rem;
  margin-top: 1.5rem !important;
  margin-bottom: 1rem !important;
  padding-left: 1rem !important;
  padding-right: 0.8rem !important;
}
.entries li {
  margin: 0;
  border: 1.5px solid hsl(60, 20%, 80%);
}
.entries li > a {
  background: hsl(60, 20%, 90%);
  border-bottom: 1px solid hsl(60, 20%, 80%);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 18px;
  padding: 0.3rem 0.2rem;
  text-decoration: none;
}
.entries li sup a {
  display: inline;
  float: right;
}
li small {
  display: block;
  padding: 0.3rem 0.2rem;
  background: #efefef;
}
li {
position: relative;
}
li .intro {
width: 100%;
box-sizing: border-box;
position: absolute;
height: 0;
text-overflow: hidden;
overflow: hidden;
z-index: 1;
  border: 1px solid hsl(60, 20%, 80%);
background: #efefef;
margin: 0;
padding: 0;
transition: height 1s ease-in-out, padding 0.1s ease-out 1s, z-index 0s ease-out 1s;
}
li:hover .intro
{
height: 15rem;
z-index: 2;
padding: 0.4rem 0.2rem;
transition: height 1s ease-in-out, padding 0.1s ease-out 0s, z-index 0s ease-out 0s;
}
/* Review */
h2 ~ p {
  text-align: center;
}
dt {
  text-align: center;
  margin-bottom: 0.5rem;
  margin-top: 1.5rem;
}
dd {
  margin: 0;
}
blockquote {
  margin: 0;
  text-align: justify;
  padding-left: 1rem;
  padding-right: 1rem;
}
blockquote br {
  margin-bottom: 0.5rem;
}
`
const getIntro = async (url) =>
{
    const content = await fetch(url).then(res => res.text())
    const parser = new DOMParser()
    const page = parser.parseFromString(content, "text/html")
    const quote = page.querySelector("blockquote").innerText.trim().split(" ").filter(e => e)
    const intro = quote.splice(0, Math.min(50, quote.length))
    return intro.join(" ") + "..."
}
const addIntroLoader = () =>
{
    const entryUL = document.querySelector(".entries")
    const entries = [...entryUL.querySelectorAll("li")]
    entries.forEach(entry =>
    {
        const p = document.createElement("p")
        p.innerText = "Loading...";
        p.className = "intro";
        entry.appendChild(p)
        let timeout = null;
        entry.addEventListener("mouseover", () =>
        {
            if (entry.className.indexOf("handled") == -1)
            {
                const url = entry.querySelector("a").getAttribute("href");
                if (localStorage.getItem(url) !== null)
                {
                    entry.className += " handled"
                    p.innerText = localStorage.getItem(url);
                }
                else
                {
                    timeout = setTimeout(() => {
                        entry.className += " handled"
                        getIntro(url).then(intro => {
                            p.innerText = intro;
                            localStorage.setItem(url, intro);
                        })
                    }, 500)
                }
            }
        })
        entry.addEventListener("mouseout", () =>
        {
            if (timeout !== null) clearTimeout(timeout)
        })
    })
}
const sortType = Object.freeze(
    {
        ALPHABETICAL: "Sort alphabetically",
        DATENEW: "Sort by Date (Newest first)",
        DATEOLD: "Sort by Date (Oldest first)",
        COMMENTSMANY: "Sort by Most Comments",
        COMMENTSFEW: "Sort by Least Comments",
    }
)
const getSort = (elem, type) =>
{
    switch (type)
    {
        case sortType.ALPHABETICAL:
            return elem.querySelector("a").innerText;
        case sortType.DATENEW:
            return -Number(elem.querySelector("a").getAttribute("href").split("/")[2]);
        case sortType.DATEOLD:
            return Number(elem.querySelector("a").getAttribute("href").split("/")[2]);
        case sortType.COMMENTSMANY:
            return -Number(elem.querySelector("small").innerText.substring(1).split(" ")[0]);
        case sortType.COMMENTSFEW:
            return Number(elem.querySelector("small").innerText.substring(1).split(" ")[0]);
    }
    console.warn("Bad sortType!");
}
const injectStyle = () =>
{
    const styleElem = document.createElement("style");
    styleElem.innerText = style;
    document.head.appendChild(styleElem);
}
const addSortBar = () =>
{
    const page = document.querySelector(".page")
    const entryUL = document.querySelector(".entries")
    const entries = [...entryUL.querySelectorAll("li")]
    let isSorted = false;
    let isReverse = true;
    const select = document.createElement("select");
    for (let value of Object.values(sortType))
    {
        const option = document.createElement("option");
        option.setAttribute("value", value);
        option.innerText = value;
        select.appendChild(option);
    }
  
    select.value = window.localStorage.getItem("selected") ?? sortType.DATENEW
    const button = document.createElement("button")
    button.textContent = "Sort"
    button.addEventListener("click", () =>
    {
        entries.sort((first, second) => {
            const f = getSort(first, select.value)
            const s = getSort(second, select.value)
            
            if (select.value != sortType.ALPHABETICAL)
              return Math.sign(f - s)
          
            return f.localeCompare(s);
        })
        while (entryUL.firstChild)
        {
            entryUL.firstChild.remove()
        }
        entries.forEach(e => entryUL.appendChild(e))
        window.localStorage.setItem("selected", select.value)
    })
  
    button.click()
    const div = document.createElement("div");
    div.className = "sorter";
    div.appendChild(select);
    div.appendChild(button);
    page.insertBefore(div, entryUL)
}
const fixLinks = () =>
{
    const links = document.querySelectorAll("a");
    links.forEach(link => {
        const url = link.getAttribute("href")?.split("/")
        if (url !== undefined && url[2] == "boards.4chan.org")
        {
            url[2] = "desuarchive.org";
            // replace quote anchor's p with q for desuarchive.org
            let anchor = url[url.length-1].split("#");
            anchor[1] = "q" + anchor[1].substring(1)
            url[url.length-1] = anchor.join("#")
            link.setAttribute("href", url.join("/"))
        }
    })
}
const makeHeader = () =>
{
  const lis = [...document.querySelectorAll(".entries li")];
  const length = lis.length
  const totalReviews = lis.map(e => Number(e.querySelector("small").innerText.split(" ")[0].split("(")[1])).reduce((prev, curr) => prev+curr)
  
  document.querySelector("h2").innerHTML+= `
(${length} Fics / ${totalReviews} Reviews)`
}
(function() {
    'use strict';
    injectStyle(style);
    if (window.location.toString().split("/").length == 4)
    {
        addSortBar();
        addIntroLoader();
        makeHeader();
    }
    else
    {
        fixLinks()
    }
})();