import { extractErrorMsg, delay, pickRandom_Letters } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { getRandomInRange } from './helpers.mjs';
import { GLOBAL_LOG_A_LOT, MICROBE_AGE_MAX_MS, MICROBE_AGE_MIN_MS, MICROBE_COUNT_INITIAL, MICROBE_COUNT_MAX, MICROBE_MITOSIS_PROBABILITY_PER_ANIMATE, MICROBE_SIZE_MAX, MICROBE_SIZE_MIN, SCROLL_TWEAKER_DECAY, SCROLL_TWEAKER_DECAY_INTERVAL_MS, SCROLL_TWEAKER_MAX, SCROLL_TWEAKER_MIN, SCROLL_TWEAKER_STEP, } from './constants.mjs';
import { AUTO_GENERATED_VERSION } from './AUTO-GENERATED-version.mjs';
import { linkEntries } from './links.mjs';
const logalot = GLOBAL_LOG_A_LOT;
console.log(`version: ${AUTO_GENERATED_VERSION}`);
// tweak the motion but diminish over time
let scrollTweaker = 0.0;
function initializeScrollTweaker() {
    window.addEventListener('scroll', function () {
        scrollTweaker += SCROLL_TWEAKER_STEP;
        if (scrollTweaker > SCROLL_TWEAKER_MAX) {
            scrollTweaker = SCROLL_TWEAKER_MAX;
        }
    });
    setInterval(() => {
        scrollTweaker *= SCROLL_TWEAKER_DECAY;
        if (scrollTweaker < SCROLL_TWEAKER_MIN) {
            scrollTweaker = SCROLL_TWEAKER_MIN;
        }
    }, SCROLL_TWEAKER_DECAY_INTERVAL_MS);
}
initializeScrollTweaker();
const svgContainer = document.getElementById('background-svg-container');
let initializingMicrobes = false;
let microbes = [];
let removedIds = [];
const fnRemoveMicrobe = (svg) => {
    if (!removedIds.includes(svg.id)) {
        microbes = microbes.filter(x => x.id !== svg.id);
        removedIds.push(svg.id);
        svgContainer.removeChild(svg);
    }
};
// remove all the microbes every intervalMs
const wipeoutAllMs = 10000;
setInterval(() => {
    microbes.forEach(m => { fnRemoveMicrobe(m); });
}, wipeoutAllMs);
async function initializeMicrobes() {
    const lc = `[${initializeMicrobes.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: a66439a58226d6d1ae42fe7a729abf24)`);
        }
        if (initializingMicrobes) {
            console.log(`${lc} already initializing microbes. (I: df7fa64ae9954fdd9ccfa5797cade51a)`);
            return; /* <<<< returns early */
        }
        else {
            initializingMicrobes = true;
        }
        async function createMicrobe() {
            if (microbes.length >= MICROBE_COUNT_MAX) {
                console.log(`${lc} max microbes already hit. (I: f1a49562ae204bf1adda6317561b124d)`);
                return; /* <<<< returns early */
            }
            const svgNS = "http://www.w3.org/2000/svg";
            const svg = document.createElementNS(svgNS, "svg");
            svg.id = pickRandom_Letters({ count: 8 });
            microbes.push(svg);
            const microbeAgeMs = getRandomInRange({
                min: MICROBE_AGE_MIN_MS,
                max: MICROBE_AGE_MAX_MS,
            });
            svg.onclick = () => { fnRemoveMicrobe(svg); };
            const pattern = document.createElementNS(svgNS, "pattern");
            const circle = document.createElementNS(svgNS, "circle");
            const group = document.createElementNS(svgNS, "g");
            const rect = document.createElementNS(svgNS, "rect");
            // Randomize position and size
            const paddingX = 0.03 * svgContainer.clientWidth;
            const paddingY = 0.03 * svgContainer.clientHeight;
            // Math.random isn't close to random and favors down and right (bottom
            // right quadrant) so we shift it a bit.
            let xPos = Math.random() * (svgContainer.clientWidth - (paddingX));
            let yPos = Math.random() * (svgContainer.clientHeight - (paddingY));
            xPos -= 0.5 * svgContainer.clientWidth;
            // yPos -= 0.2 * svgContainer.clientHeight;
            const size = MICROBE_SIZE_MIN + (Math.random() * (MICROBE_SIZE_MAX - MICROBE_SIZE_MIN));
            // Random initial rotation
            const initialRotation = Math.random() * 360;
            svg.setAttribute("width", `${size}`);
            svg.setAttribute("height", `${size}`);
            svg.setAttribute("viewBox", "0 0 100 100");
            svg.style.position = "absolute";
            svg.style.left = `${xPos}px`;
            svg.style.top = `${yPos}px`;
            pattern.setAttribute("id", `microbePattern-${Math.random()}`); // Unique ID for each
            pattern.setAttribute("width", "100");
            pattern.setAttribute("height", "100");
            pattern.setAttribute("patternUnits", "userSpaceOnUse");
            circle.setAttribute("cx", "50");
            circle.setAttribute("cy", "50");
            circle.setAttribute("r", "20");
            // color of the microbes
            // make the microbe more see-through at the top of the page for
            // initial landing readability...trying to avoid background color
            // for header
            if (yPos < svgContainer.clientHeight * 0.2) {
                circle.setAttribute("fill", "#41da4112");
            }
            else {
                circle.setAttribute("fill", "#41da4158");
            }
            let ciliaColor = "#90dd6a";
            if (yPos < svgContainer.clientHeight * 0.2) {
                ciliaColor = "#90dd6a38";
            }
            const numCilia = 16; // Number of cilia
            const ciliaRadius = 18; // Radius from the center of the microbe
            const waveAmplitude = 5; // Adjust for wave intensity
            const waveFrequency = 2; // Adjust for number of waves
            group.setAttribute("transform", "translate(50,50)");
            for (let i = 0; i < numCilia; i++) {
                const angle = (i / numCilia) * 2 * Math.PI; // Angle in radians
                const startX = ciliaRadius * Math.cos(angle);
                const startY = ciliaRadius * Math.sin(angle);
                const endX = (ciliaRadius + Math.random() * 5 + 3) * Math.cos(angle);
                const endY = (ciliaRadius + Math.random() * 5 + 3) * Math.sin(angle);
                // Calculate control points for the wavy path
                const controlX1 = startX + waveAmplitude * Math.cos(angle * waveFrequency);
                const controlY1 = startY + waveAmplitude * Math.sin(angle * waveFrequency);
                const controlX2 = endX + waveAmplitude * Math.cos(angle * waveFrequency + Math.PI);
                const controlY2 = endY + waveAmplitude * Math.sin(angle * waveFrequency + Math.PI);
                // Create path element
                const path = document.createElementNS(svgNS, "path");
                path.setAttribute("d", `M ${startX} ${startY} C ${controlX1} ${controlY1}, ${controlX2} ${controlY2}, ${endX} ${endY}`);
                path.setAttribute("stroke", ciliaColor);
                path.setAttribute("stroke-width", "2");
                path.setAttribute("stroke-linecap", "round");
                path.setAttribute("fill", "transparent"); // Make sure the path doesn't fill
                group.appendChild(path);
            }
            rect.setAttribute("width", "100%");
            rect.setAttribute("height", "100%");
            rect.setAttribute("fill", `url(#${pattern.id})`);
            pattern.appendChild(circle);
            pattern.appendChild(group);
            svg.appendChild(pattern);
            svg.appendChild(rect);
            svgContainer.appendChild(svg);
            // Apply initial rotation
            svg.style.transform = `rotate(${initialRotation}deg)`;
            // --- Movement Properties ---
            const speedMultiplier = size * 0.01 + (Math.random() * 0.05);
            // Animate on scroll AND add idle drift
            function animateMicrobe() {
                let xDirection = Math.random() < 0.5 ? -1 : 1;
                let yDirection = Math.random() < 0.5 ? -1 : 1;
                xPos += xDirection * scrollTweaker * speedMultiplier * 0.01;
                yPos += yDirection * scrollTweaker * speedMultiplier * 0.01;
                // Update position and rotation
                // --- Boundary Check & New Microbe Creation ---
                if (xPos < 0 + (0.3 * paddingX) ||
                    (xPos > svgContainer.clientWidth - paddingX) ||
                    (yPos < 0 + paddingY) || (yPos > svgContainer.clientHeight - paddingY)) {
                    // Remove the microbe too close to the edge
                    fnRemoveMicrobe(svg);
                }
                else {
                    // --- Cilia Rotation (apply only to this microbe's cilia) ---
                    // Example: Update cilia rotation to target 'path'
                    const cilia = group.querySelectorAll('path'); // Select all cilia paths within the group
                    cilia.forEach(cilium => {
                        var _a;
                        if (Math.random() > 0.7) {
                            (_a = cilium).ibgibRotation ?? (_a.ibgibRotation = Math.random() * 360); // degrees
                            const newRotation = 360 % (cilium.ibgibRotation + (Math.random() * scrollTweaker));
                            cilium.style.transform = `rotate(${newRotation}deg)`;
                            cilium.ibgibRotation = newRotation;
                        }
                    });
                    svg.style.transform = `translate(${xPos}px, ${yPos}px)`;
                    if (Math.random() < (MICROBE_MITOSIS_PROBABILITY_PER_ANIMATE / (microbes.length / 2))) {
                        createMicrobe();
                    }
                    requestAnimationFrame(animateMicrobe);
                }
            }
            setTimeout(async () => {
                fnRemoveMicrobe(svg);
            }, microbeAgeMs);
            animateMicrobe(); // Start the animation loop
        }
        for (let i = 0; i < MICROBE_COUNT_INITIAL; i++) {
            await delay(100);
            createMicrobe();
        }
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
        initializingMicrobes = false;
    }
}
initializeMicrobes();
/**
 * creates the html elements for the links and adds them to the DOM
 * @param links
 */
function renderLinks(links) {
    const mainElement = document.querySelector('main');
    const groupedLinks = links.reduce((acc, link) => {
        if (!acc[link.group]) {
            acc[link.group] = [];
        }
        acc[link.group].push(link);
        return acc;
    }, {});
    for (const [groupName, groupLinks] of Object.entries(groupedLinks)) {
        const groupDiv = document.createElement("div");
        groupDiv.classList.add("group");
        mainElement.appendChild(groupDiv);
        const groupHeader = document.createElement("h2");
        groupHeader.textContent = groupName;
        groupHeader.classList.add("group-header");
        groupDiv.appendChild(groupHeader);
        const groupList = document.createElement("ul");
        groupList.classList.add("link-list");
        groupLinks.forEach(link => {
            const listItem = document.createElement("li");
            listItem.classList.add("entry-li");
            if (link.url) {
                listItem.innerHTML = `<div class=entry-div>
                        <div class="link-info">
                            <span class="name">${link.name}</span>
                            <span class="modified">${link.modified}</span>
                        </div>
                        <div class="copy-button-and-link">
                            <button class="copy-button" data-url="${link.url}" title="Copy Link">⎘</button>
                            <a class="raw-url" href="${link.url}" target="_blank">${link.url}</a>
                        </div>
                        <div class="description">${link.description}</div>
                    </div>`;
                listItem.style.zIndex = "100";
            }
            else if (link.ibGibAddr) {
                listItem.innerHTML = `<div class=entry-div>
                        <div class="link-info">
                            <span class="name">${link.name}</span>
                            <span class="modified">${link.modified}</span>
                        </div>
                        <div class="copy-button-and-link">
                            <button class="copy-button" data-url="${link.ibGibAddr}" title="Copy Link">⎘</button>
                            <span class="raw-url">${link.ibGibAddr}</span>
                        </div>
                        <p class="description">${link.description}</p>
                    </div>`;
                listItem.style.zIndex = "100";
            }
            else {
                console.error(`linkEntry has neither url nor ibGibAddr? (E: 058f1c81a6094ea2a38bcd92af8d12e7)`);
                console.dir(link);
            }
            groupList.appendChild(listItem);
        });
        groupDiv.appendChild(groupList);
    }
    // Add copy button click event listeners after rendering
    const copyButtons = document.querySelectorAll('.copy-button');
    copyButtons.forEach(button => {
        button.addEventListener('click', (event) => {
            const target = event.currentTarget;
            if (target instanceof HTMLElement) {
                const urlToCopy = target.dataset.url ?? target.dataset.ibGibAddr;
                // Create a temporary text area
                const tempTextArea = document.createElement('textarea');
                tempTextArea.value = urlToCopy;
                document.body.appendChild(tempTextArea);
                // Select the text and copy
                tempTextArea.focus();
                tempTextArea.select();
                try {
                    document.execCommand('copy'); // Execute the copy command
                    // Optional: Provide feedback to the user
                    target.textContent = "copied";
                    setTimeout(() => {
                        target.innerHTML = "⎘"; // Reset button text
                    }, 2000);
                }
                catch (err) {
                    console.error("Failed to copy: ", err);
                }
                finally {
                    // Remove the temporary text area
                    document.body.removeChild(tempTextArea);
                }
            }
        });
    });
    // Accordion functionality
    const groupHeaders = document.querySelectorAll('.group-header');
    groupHeaders.forEach(header => {
        header.addEventListener('click', () => {
            const linkList = header.nextElementSibling; // Get the adjacent <ul>
            // linkList.style.display = linkList.style.display === 'none' ? 'block' : 'none';
            linkList.style.display =
                linkList.style.display === 'none' || linkList.style.display === '' ?
                    'block' :
                    'none';
        });
    });
}
renderLinks(linkEntries);
function initializeResizeObserver() {
    const resizeObserver = new ResizeObserver(entries => {
        initializeMicrobes();
        setTimeout(() => {
            initializeMicrobes();
        }, 1500);
    });
    resizeObserver.observe(document.body);
}
initializeResizeObserver();
