import { marked } from 'https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js'

const body = document.body

async function loadPage(x = 0, y = 0) {
    const urlString = window.location.search;
    let pageName = urlString.split('?')[1];

    if(!pageName || !(/^[A-Za-z0-9_]+$/.test(pageName))) {
        pageName = "home_page"
        window.location.search = "?home_page"
        window.history.pushState("home_page", "", window.location)
    }

    const text = await requestPage(pageName);
    const steps = await stepThroughPage(pageName);
    renderPage(pageName, text, steps, x, y);
}

async function stepThroughPage(pageName) {
    const step = await fetch(`/loam/step/${pageName}.txt`, { method: 'post' });
    if(!step.ok) { console.log("Unable to leave footprints here :("); }
    const getSteps = await fetch(`/hidden/footsteps/${pageName}.txt`);
    if(!getSteps.ok) { console.log("Unable to figure out how many steps are here :("); return "an unknown number of " }
    return getSteps.text();
}

async function requestPage(pageName) {
    const fileName = pageName.replaceAll("__", "/") + ".md";
    
    const response = await fetch(fileName);

    if(!response.ok) {
        return "This page does not exist!"
    }
    
    return response.text();
}

async function preprocessMarkdown(markdown) {
    // parse the initial {{{ frontmatter }}}
    let frontmatter = null;

    markdown = markdown.trimStart();
    if (markdown.startsWith("{{{")) {
        let begin = markdown.indexOf("{{{") + 2;
        let end = markdown.indexOf("}}}") + 1;
        // console.log(`begin: ${begin} end: ${end}`);
        // console.log(markdown.slice(begin, end));
        
        // parse frontmatter JSON
        frontmatter = JSON.parse(markdown.slice(begin, end));
        
        // remove frontmatter
        markdown = markdown.slice(end + 2);
    }

    // use frontmatter to add page stylings
    if (frontmatter) {
        const title = frontmatter.title ? `# ${frontmatter.title}\n---\n\n` : "";

        const status = frontmatter.status ? `*<a class="metadata" href="?metadata">status: ${frontmatter.status}</a>*\n\n---\n\n` : "";

        let metadata = (frontmatter.nobreak ? "" : "\n---") + `\n\n*<a class="metadata" href="?metadata"><p>`;
        if (frontmatter.last_tended_to) {
            metadata += `last tended to: ${frontmatter.last_tended_to}`;
        }

        if (frontmatter.repotted) {
            if(!metadata.endsWith("<p>")) { // not the first metadata item
                metadata += "<br>";
            }
            metadata += `repotted: ${frontmatter.repotted}`;
        }
        if (frontmatter.planted) {
            if(!metadata.endsWith("<p>")) { // not the first metadata item
                metadata += "<br>";
            }
            metadata += `planted: ${frontmatter.planted}`;
        }
        metadata += "</p></a>*";

        if (frontmatter.allow_inline) {
            const matches = markdown.match(/\[\[.+\]\]/g);

            let i = 0;

            for(let match of matches) {
                match = match.slice(2, -2);
                
                if(i < 2) { // synchronously load the first few inlines
                    let subpage = await requestPage(`${match}`);
                    subpage = await preprocessMarkdown(subpage);
                    markdown = markdown.replace(`[[${match}]]`, subpage);
                }
                else { // replace the rest with placeholders to be loaded slowly
                    markdown = markdown.replace(`[[${match}]]`, 
                        `<p id="placeholder-${match}"></p>`
                    )
                    requestPage(match)
                        .then((text) => preprocessMarkdown(text))
                        .then((md) => {
                            const placeholder = document.getElementById(`placeholder-${match}`);
                            placeholder.outerHTML = marked.parse(md);
                        });
                }
                
                i++;
            }
        }

        markdown = title + status +  markdown + metadata;
    }

    return markdown;
}

async function renderPage(title, markdown, steps, x = 0, y = 0) {
    let clientWidth = window.innerWidth;

    // make sure a page isn't wider than the screen
    const pageWidth = Math.min(400, clientWidth - 20);

    // make sure that small screens can still get the corkboard effect
    if(clientWidth < pageWidth * 2) {
        clientWidth = pageWidth * 2;
    }

    if(x + pageWidth + 20 > clientWidth) { 
        // offset the page by the amount it would've been pushed off the page.
        x -= ((x + pageWidth + 20) - clientWidth) * 2;
    }
    x = Math.max(0, Math.min(x, clientWidth - pageWidth - 20))

    let page = document.createElement("div");
    page.id = title;
    page.className = "page";
    page.style = `width: ${pageWidth}px; left: ${x}px; top: ${y}px`;
    
    markdown = await preprocessMarkdown(markdown);
    if(steps) {
        markdown += `<p>*this page has been passed through ${steps}`
        markdown += steps === "1" ? " time" : " times"
        markdown += "*<p>"
    }
    
    page.innerHTML = marked.parse(markdown);

    body.appendChild(page);
}

// satisfies the following constraints for a container:
// 1. The container cannot be *outside the screen bounds*
//   a. If this means resizing the container width, do so
// 2. The container must be underneath the mouse pointer (with the container top placed aligned with it)
// returns { x = <top left X value>, y = <top left y value>, width = <modified container width> }
function placeContainer(width, mouseX, mouseY) {
    // TODO ( i got lazy )
}

async function renderImageDetail(source, width, x = 0, y = 0) {
    let clientWidth = window.visualViewport.width;

    if (width < 400) width = 400;

    // make sure a page isn't wider than the screen
    const pageWidth = Math.min(width, clientWidth - 20);

    // start by putting the image in the center of the screen
    let newX = window.visualViewport.offsetLeft + clientWidth / 2 - width / 2;
    
    // make sure the mouse pointer is past the *left edge* of the image
    if(x < newX) newX = x;
    // make sure the mouse pointer is before the *right edge* of the image
    if(newX + pageWidth < x) newX = x - pageWidth;
    // make sure the page is not off screen either direction
    if(newX < window.visualViewport.offsetLeft) newX = 0;
    if(newX + pageWidth > window.visualViewport.offsetLeft + clientWidth) newX = clientWidth - pageWidth;


    let page = document.createElement("div");
    page.id = source;
    page.className = "page";
    page.style = `width: ${pageWidth}px; left: ${newX}px; top: ${y}px`;
    let img = document.createElement("img");
    page.appendChild(img);
    img.src = source;
    img.className = "imgDetail";
    
    body.appendChild(page);
}


window.addEventListener('popstate', (event) => {
    if(event.state) { 
        const name = event.state;
        const matches = document.querySelectorAll(`#${name}`);
        const keep = matches[matches.length - 1];
        if(keep) {
            while(keep.nextElementSibling) {
                keep.nextElementSibling.remove();
            }
        } else { // no pages remaining, just reload the one requested.
            loadPage();
        }
    }
});

window.addEventListener('click', (event) => {
    // console.log(event.target.tagName);
    if(event.target.tagName === "A") {
        const url = event.target.href;
        if(!url.includes('hotn.gay') || url.includes('mailto')) { return; }
        
        event.preventDefault();
        
        let page = url.split("?")[1]
        if(page != window.history.state) window.history.pushState(page, "", url);
        
        loadPage(event.pageX, event.pageY);
    } else if(event.target.tagName === "IMG") {
        if(event.target.className === "imgDetail") { event.target.parentElement.remove(); return; }
        let src = event.target.src;

        if(document.getElementById(src)) { document.getElementById(src).remove(); }
        
        let width = event.target.naturalWidth + 20;
        renderImageDetail(src, width, event.pageX, event.pageY);
    } else {
        let keep = event.target.closest('.page');
        if(keep) {
            window.history.pushState(keep.id, "", `?${keep.id}`)
            while(keep.nextElementSibling) {
                keep.nextElementSibling.remove();
            }
        }
    }
})

loadPage();