
window.requestAnimFrame = (function () {
  return window.requestAnimationFrame
    || window.webkitRequestAnimationFrame
    || window.mozRequestAnimationFrame
    || function (callback) { window.setTimeout(callback, 1000 / 60); };
})();

(() => {
  let video;

  // User dropdown toggle
  const userToggle = document.getElementById('nav-user-toggle');
  const userMenu = document.getElementById('nav-user-menu');
  if (userToggle && userMenu) {
    userToggle.addEventListener('click', (e) => {
      e.stopPropagation();
      userMenu.classList.toggle('show');
    });
    document.addEventListener('click', (e) => {
      if (!userMenu.contains(e.target) && !userToggle.contains(e.target)) {
        userMenu.classList.remove('show');
      }
    });
  }

  // Initialize background preference
  if (localStorage.getItem('background') == undefined) {
    localStorage.setItem('background', 'true');
  }
  var background = localStorage.getItem('background') === 'true';
  // Apply initial visual state
  var initialCanvas = document.getElementById('bg');
  if (initialCanvas) {
    if (background) {
      initialCanvas.classList.add('fader-in');
      initialCanvas.classList.remove('fader-out');
    } else {
      initialCanvas.classList.add('fader-out');
      initialCanvas.classList.remove('fader-in');
    }
  }


  if (elem = document.querySelector("#my-video")) {
    video = new v0ck(elem);
    document.addEventListener("keydown", e => {
      if (e.key === " " && e.target.tagName !== "INPUT" && e.target.tagName !== "TEXTAREA") {
        video[video.paused ? 'play' : 'pause']();
        document.querySelector('.v0ck_overlay').classList[video.paused ? 'remove' : 'add']('v0ck_hidden');
      }
    });



    if (elem !== null) {
      // ... existing code ...
    }
  }

  // Export init function for dynamic calls
  window.initBackground = () => {
    // Re-fetch elements as they might have been replaced
    const elem = document.querySelector("#my-video");
    const canvas = document.getElementById('bg');

    if (elem) {
      // Initialize video wrapper if needed or just get instance
      // Assuming v0ck handles re-init or we just use raw element for events
      // But video variable is local.
      // We need to re-bind 'play' event if it's a new element.

      if (canvas) {
        // Restore visual state on re-init
        if (background) {
          canvas.classList.add('fader-in');
          canvas.classList.remove('fader-out');
        } else {
          canvas.classList.add('fader-out');
          canvas.classList.remove('fader-in');
        }

        const context = canvas.getContext('2d');
        const cw = canvas.width = canvas.clientWidth | 0;
        const ch = canvas.height = canvas.clientHeight | 0;

        const animationLoop = () => {
          if (elem.paused || elem.ended || !background)
            return;
          context.drawImage(elem, 0, 0, cw, ch);
          window.requestAnimFrame(animationLoop);
        }

        elem.addEventListener('play', animationLoop);

        if (!elem.paused) {
          animationLoop();
        }
      }
    }
  };

  // Initial call
  window.initBackground();

  const loadPageAjax = async (url) => {
    // Show loading indicator
    const navbar = document.querySelector("nav.navbar");
    if (navbar) navbar.classList.add("pbwork");

    try {
      // Extract page number, user, tag, etc.
      let page = 1;
      const pMatch = url.match(/\/p\/(\d+)/);
      if (pMatch) page = pMatch[1];

      // Extract context
      let tag = null, user = null, mime = null;
      const tagMatch = url.match(/\/tag\/([^/]+)/);
      if (tagMatch) tag = decodeURIComponent(tagMatch[1]);

      const userMatch = url.match(/\/user\/([^/]+)/);
      if (userMatch) user = decodeURIComponent(userMatch[1]);

      const mimeMatch = url.match(/\/(image|audio|video)/);
      if (mimeMatch) mime = mimeMatch[1];

      let ajaxUrl = `/ajax/items/?page=${page}`;
      if (tag) ajaxUrl += `&tag=${encodeURIComponent(tag)}`;
      if (user) ajaxUrl += `&user=${encodeURIComponent(user)}`;
      if (mime) ajaxUrl += `&mime=${encodeURIComponent(mime)}`;

      console.log("Fetching Page:", ajaxUrl);
      const response = await fetch(ajaxUrl, { credentials: 'include' });
      const data = await response.json();

      if (data.success) {
        // Replace grid content
        // If "infinite scroll" we might append, but pagination implies jumping properly? 
        // User said "resembled in pagination", which implies staying in sync.
        // If I click Next Page, I expect to SEE page 2.
        // But infinite scroll usually appends.
        // Let's implement REPLACE for explicit page navigation to be safe/standard.
        // Wait, the "infinite scroll" feature usually implies APPEND. 
        // If the user wants infinite scroll, they shouldn't click pagination?
        // But if they scroll, `changePage` is called which clicks `.next`.
        // So if I replace content, it breaks infinite scroll flow (items disappear).
        // So I should APPEND if it's "next page" and we are already on the page?
        // But `changePage` is triggered by scroll.
        // Let's APPEND.

        const posts = document.querySelector('.posts');
        if (posts) {
          // Check if we are appending (next page) or jumping
          // For simple "infinite scroll", we append.
          posts.insertAdjacentHTML('beforeend', data.html);
        }

        // Update pagination
        if (data.pagination) {
          document.querySelectorAll('.pagination-wrapper').forEach(el => el.innerHTML = data.pagination);
        }

        // Update History
        history.pushState({}, '', url);
      }

    } catch (err) {
      console.error(err);
      window.location.href = url; // Fallback
    } finally {
      if (navbar) navbar.classList.remove("pbwork");
      // Restore pagination visibility for Grid View
      const navPag = document.querySelector('.pagination-container-fluid');
      if (navPag) navPag.style.display = '';
    }
  };

  let tt = false;
  const stimeout = 500;

  const setupMedia = () => {
    if (elem = document.querySelector("#my-video")) {
      video = new v0ck(elem);
    }
  };

  // Navbar scroll effect - make background black when scrolling
  const navbar = document.querySelector('.navbar');
  if (navbar) {
    window.addEventListener('scroll', () => {
      if (window.scrollY > 50) {
        navbar.classList.add('scrolled');
      } else {
        navbar.classList.remove('scrolled');
      }
    });
  }

  const loadItemAjax = async (url, inheritContext = true) => {
    console.log("loadItemAjax called with:", url, "inheritContext:", inheritContext);
    // Show loading indicator
    const navbar = document.querySelector("nav.navbar");
    if (navbar) navbar.classList.add("pbwork");

    // Extract item ID from URL. Regex now handles query params, hashes, and trailing slashes.
    const match = url.match(/\/(\d+)(?:\/|#|\?|$)/);

    // Hide navbar pagination for Item View (matches SSR)
    const navPag = document.querySelector('.pagination-container-fluid');
    if (navPag) navPag.style.display = 'none';

    if (!match) {
      console.warn("loadItemAjax: No ID match found in URL", url);
      // fallback for weird/external links
      window.location.href = url;
      return;
    }
    const itemid = match[1];

    // <context-preservation>
    // Extract context from Target URL first
    let tag = null, user = null, isFavs = false;
    const tagMatch = url.match(/\/tag\/([^/]+)/);
    if (tagMatch) tag = decodeURIComponent(tagMatch[1]);

    const userMatch = url.match(/\/user\/([^/]+)/);
    if (userMatch) {
      user = decodeURIComponent(userMatch[1]);
      if (url.match(/\/user\/[^/]+\/favs(\/|$|\?)/)) isFavs = true;
    }

    // If missing and inheritContext is true, check Window Location
    if (inheritContext) {
      if (!tag) {
        const wTagMatch = window.location.href.match(/\/tag\/([^/]+)/);
        if (wTagMatch) tag = decodeURIComponent(wTagMatch[1]);
      }
      if (!user) {
        const wUserMatch = window.location.href.match(/\/user\/([^/]+)/);
        if (wUserMatch) {
          user = decodeURIComponent(wUserMatch[1]);
          // Check for /favs (with or without trailing /, item id, or query params)
          if (window.location.href.match(/\/user\/[^/]+\/favs(\/|$|\?)/)) isFavs = true;
        }
      }
    }
    // </context-preservation>

    try {
      // Construct AJAX URL
      let ajaxUrl = `/ajax/item/${itemid}`;

      const params = new URLSearchParams();
      if (tag) params.append('tag', tag);
      if (user) params.append('user', user);
      if (isFavs) params.append('fav', 'true');

      if ([...params].length > 0) {
        ajaxUrl += '?' + params.toString();
      }

      console.log("Fetching:", ajaxUrl);
      const response = await fetch(ajaxUrl, { credentials: 'include' });
      if (!response.ok) throw new Error(`Network response was not ok: ${response.status}`);

      const rawText = await response.text();
      let html, paginationHtml;

      try {
        // Optimistically try to parse as JSON first
        const data = JSON.parse(rawText);
        if (data && typeof data.html === 'string') {
          html = data.html;
          paginationHtml = data.pagination;
        } else {
          html = rawText;
        }
      } catch (e) {
        // If JSON parse fails, assume it's HTML text
        html = rawText;
      }

      let container = document.querySelector('#main .container');

      if (!container && document.querySelector('.index-container')) {
        // Transition from Index to Item View
        const main = document.getElementById('main');
        main.innerHTML = '<div class="container"></div>';
        container = main.querySelector('.container');
      } else if (!container && document.getElementById('main')) {
        // Transition from User Profile or other pages without .container
        const main = document.getElementById('main');
        main.innerHTML = '<div class="container"></div>';
        container = main.querySelector('.container');
      } else if (container) {
        // Check if we are on Tags Overview logic (which reuses .container)
        const tagsOverview = container.querySelector('.tags');
        if (tagsOverview) {
          container.innerHTML = '';
        } else {
          // Already in Item View, clear usage
          const oldContent = container.querySelector('.content');
          const oldMetadata = container.querySelector('.metadata');
          const oldHeader = container.querySelector('._204863');
          if (oldHeader) oldHeader.remove();
          if (oldContent) oldContent.remove();
          if (oldMetadata) oldMetadata.remove();
        }
      }

      container.insertAdjacentHTML('beforeend', html);

      // Update pagination if present
      if (paginationHtml) {
        const pagWrappers = document.querySelectorAll('.pagination-wrapper');
        pagWrappers.forEach(el => el.innerHTML = paginationHtml);
      }

      // Construct proper History URL (Context Aware)
      // If we inherited context, we should reflect it in the URL
      let pushUrl = `/${itemid}`;
      // Logic from ajax.mjs context reconstruction:
      if (user) {
        pushUrl = `/user/${user}/${itemid}`;
        if (isFavs) pushUrl = `/user/${user}/favs/${itemid}`;
      }
      else if (tag) pushUrl = `/tag/${tag}/${itemid}`;

      // We overwrite proper URL even if the link clicked was "naked"
      history.pushState({}, '', pushUrl);

      setupMedia();
      if (window.initBackground) window.initBackground();
      // Try to extract ID from response if possible or just use itemid
      document.title = `f0bm - ${itemid}`;
      if (navbar) navbar.classList.remove("pbwork");
      console.log("AJAX load complete");

    } catch (err) {
      console.error("AJAX load failed:", err);
    }
  };

  const changePage = (e, pbwork = true) => {
    if (pbwork) {
      const nav = document.querySelector("nav.navbar");
      if (nav) nav.classList.add("pbwork");
    }
    // Trigger native click for navigation
    e.click();
  };

  // Intercept clicks
  document.addEventListener('click', (e) => {

    // Check for thumbnail links on index page
    const thumbnail = e.target.closest('.posts > a');
    if (thumbnail && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
      e.preventDefault();
      // Thumbnails inherit context (e.g. from Tag Index)
      loadItemAjax(thumbnail.href, true);
      return;
    }

    const link = e.target.closest('#next, #prev, #random, #nav-random, .id-link, .nav-next, .nav-prev');
    if (link && link.href && link.hostname === window.location.hostname && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
      // Special check for random
      if (link.id === 'random' || link.id === 'nav-random') {
        e.preventDefault();
        const nav = document.querySelector("nav.navbar");
        if (nav) nav.classList.add("pbwork");

        // Extract current context from window location
        let randomUrl = '/api/v2/random';
        const params = new URLSearchParams();

        const wTagMatch = window.location.href.match(/\/tag\/([^/]+)/);
        if (wTagMatch) params.append('tag', decodeURIComponent(wTagMatch[1]));

        const wUserMatch = window.location.href.match(/\/user\/([^/]+)/);
        if (wUserMatch) {
          params.append('user', decodeURIComponent(wUserMatch[1]));
          if (window.location.href.match(/\/favs(\/|$|\?)/)) {
            params.append('fav', 'true');
          }
        }

        if ([...params].length > 0) {
          randomUrl += '?' + params.toString();
        }

        fetch(randomUrl)
          .then(r => r.json())
          .then(data => {
            if (data.success && data.items && data.items.id) {
              // Inherit context so URL matches current filter
              loadItemAjax(`/${data.items.id}`, true);
            } else {
              window.location.href = link.href;
            }
          })
          .catch((err) => {
            console.error("Random fetch failed:", err);
            window.location.href = link.href;
          });
        return;
      }

      // Standard item links
      e.preventDefault();
      if (link.href.match(/\/p\/\d+/) || link.href.match(/[?&]page=\d+/)) {
        loadPageAjax(link.href);
      } else {
        loadItemAjax(link.href, true);
      }
    } else if (e.target.closest('#togglebg')) {
      e.preventDefault();
      background = !background;
      localStorage.setItem('background', background.toString());
      var canvas = document.getElementById('bg');
      if (canvas) {
        if (background) {
          canvas.classList.remove('fader-out');
          canvas.classList.add('fader-in');
          // Re-trigger loop if started completely fresh or paused
          if (video && !video.paused) {
            // We need to access animationLoop from closure? 
            // Accessing it via window.initBackground might be cleaner or just restart it.
            // But initBackground defines it locally.
            // We can just rely on initBackground being called or canvas update.
            // Actually, if we just change opacity, the loop doesn't need to stop/start technically, 
            // but for performance we stopped it if !background.
            // So we should restart it.
            window.initBackground();
          }
        } else {
          canvas.classList.remove('fader-in');
          canvas.classList.add('fader-out');
        }
      }
    } else if (e.target.closest('.removetag')) {
      e.preventDefault();
      const removeBtn = e.target.closest('.removetag');
      const tagLink = removeBtn.previousElementSibling;

      if (tagLink) {
        const tagName = tagLink.textContent.trim();
        const idLink = document.querySelector('.id-link');
        const id = idLink ? idLink.textContent.trim() : null;

        if (id && tagName) {
          const modal = document.getElementById('delete-tag-modal');
          const nameEl = document.getElementById('delete-tag-name');
          const confirmBtn = document.getElementById('delete-tag-confirm');
          const cancelBtn = document.getElementById('delete-tag-cancel');

          if (modal) {
            nameEl.textContent = tagName;
            modal.style.display = 'flex';

            const closeModal = () => {
              modal.style.display = 'none';
              confirmBtn.onclick = null;
              cancelBtn.onclick = null;
            };

            cancelBtn.onclick = closeModal;

            confirmBtn.onclick = () => {
              confirmBtn.textContent = 'Deleting...';
              confirmBtn.disabled = true;
              fetch(`/api/v2/admin/${id}/tags/${encodeURIComponent(tagName)}`, {
                method: 'DELETE'
              })
                .then(r => r.json())
                .then(data => {
                  if (data.success) {
                    removeBtn.parentElement.remove();
                    closeModal();
                  } else {
                    alert('Error: ' + (data.msg || 'Unknown error'));
                    confirmBtn.textContent = 'Delete';
                    confirmBtn.disabled = false;
                  }
                })
                .catch(err => {
                  console.error(err);
                  alert('Failed to delete tag');
                  confirmBtn.textContent = 'Delete';
                  confirmBtn.disabled = false;
                });
            };
          }
        }
      }
    }
  });

  window.addEventListener('popstate', (e) => {
    if (window.location.href.match(/\/p\/\d+/) || window.location.href.match(/[?&]page=\d+/) || window.location.pathname === '/') {
      loadPageAjax(window.location.href);
    } else {
      loadItemAjax(window.location.href, true);
    }
  });

  // <keybindings>
  const clickOnElementBinding = selector => () => (elem = document.querySelector(selector)) ? elem.click() : null;
  const keybindings = {
    "ArrowLeft": clickOnElementBinding("#next"),
    "a": clickOnElementBinding("#next"),
    "ArrowRight": clickOnElementBinding("#prev"),
    "d": clickOnElementBinding("#prev"),
    "r": clickOnElementBinding("#random, #nav-random"),
    " ": clickOnElementBinding("#f0ck-image")
  };
  document.addEventListener("keydown", e => {
    if (e.key in keybindings && e.target.tagName !== "INPUT" && e.target.tagName !== "TEXTAREA") {
      if (e.shiftKey || e.ctrlKey || e.metaKey || e.altKey)
        return;
      e.preventDefault();
      keybindings[e.key]();
    }
  });
  // </keybindings>

  // <image-responsive>
  const imgSize = e => new Promise((res, _) => {
    const i = new Image();
    i.addEventListener('load', function () {
      res({ width: this.width, height: this.height });
    });
    i.src = e.src;
  });

  // <wheeler>
  const wheelEventListener = function (event) {
    if (event.target.closest('.media-object, .steuerung')) {
      if (event.deltaY < 0) {
        const el = document.getElementById('next');
        if (el && el.href && !el.href.endsWith('#')) el.click();
      } else if (event.deltaY > 0) {
        const el = document.getElementById('prev');
        if (el && el.href && !el.href.endsWith('#')) el.click();
      }
    }
  };

  window.addEventListener('wheel', wheelEventListener);
  // </wheeler>


  if (f0ckimage = document.querySelector("img#f0ck-image")) {
    const f0ckimagescroll = document.querySelector("#image-scroll");

    let isImageExpanded = false;
    console.log("entry point - image unclicked")

    f0ckimage.addEventListener("click", async e => {
      e.preventDefault();
      const img = await imgSize(f0ckimage);
      console.log("img clicked");
      if (isImageExpanded) {
        isImageExpanded = false;
        f0ckimagescroll.removeAttribute("style");
        f0ckimage.removeAttribute("style");
        console.log("image is not expanded")
        window.addEventListener('wheel', wheelEventListener);
      } else {
        if (img.width > img.height) return;
        isImageExpanded = true;
        window.removeEventListener('wheel', wheelEventListener);
        f0ckimagescroll.setAttribute("style", "overflow-y: scroll");
        f0ckimage.setAttribute("style", "max-height: none; height: auto; width: 100%; position: absolute; left: 0; border: var(--img-border-width) solid var(--img-border-color); border-top: none; border-bottom: none;");
      }
    });
  }
  // </image-responsive>

  // <infinite-scroll>
  const postsContainer = document.querySelector("div.posts");
  if (postsContainer) {
    // Infinite scroll state
    let infiniteState = {
      loading: false,
      hasMore: true,
      currentPage: 1
    };

    // Extract current page from URL
    const pageMatch = window.location.pathname.match(/\/p\/(\d+)/);
    if (pageMatch) infiniteState.currentPage = parseInt(pageMatch[1]);

    // Extract context (tag/user/mime) from URL
    const getContext = () => {
      const ctx = {};
      const tagMatch = window.location.pathname.match(/\/tag\/([^/]+)/);
      if (tagMatch) ctx.tag = decodeURIComponent(tagMatch[1]);
      const userMatch = window.location.pathname.match(/\/user\/([^/]+)/);
      if (userMatch) ctx.user = decodeURIComponent(userMatch[1]);
      const mimeMatch = window.location.pathname.match(/\/(image|audio|video)(?:\/|$)/);
      if (mimeMatch) ctx.mime = mimeMatch[1];
      return ctx;
    };

    // Build URL path for history
    const buildUrl = (page) => {
      const ctx = getContext();
      let path = '/';
      if (ctx.tag) path += `tag/${ctx.tag}/`;
      if (ctx.user) path += `user/${ctx.user}/`;
      if (ctx.mime) path += `${ctx.mime}/`;
      if (page > 1) path += `p/${page}`;
      return path.replace(/\/$/, '') || '/';
    };

    // Fetch and append more items
    const loadMoreItems = async () => {
      if (infiniteState.loading || !infiniteState.hasMore) return;

      infiniteState.loading = true;
      const foot = document.querySelector("div#footbar");
      if (foot) {
        foot.innerHTML = '<span class="loading-spinner">Loading...</span>';
        foot.style.color = 'var(--footbar-color)';
      }

      const nextPage = infiniteState.currentPage + 1;
      const ctx = getContext();

      const params = new URLSearchParams();
      params.append('page', nextPage);
      if (ctx.tag) params.append('tag', ctx.tag);
      if (ctx.user) params.append('user', ctx.user);
      if (ctx.mime) params.append('mime', ctx.mime);

      try {
        const response = await fetch(`/ajax/items?${params.toString()}`);
        const data = await response.json();

        if (data.success && data.html) {
          // Append new thumbnails
          postsContainer.insertAdjacentHTML('beforeend', data.html);

          // Update state
          infiniteState.currentPage = data.currentPage;
          infiniteState.hasMore = data.hasMore;

          // Update URL
          history.replaceState({}, '', buildUrl(infiniteState.currentPage));

          // Update pagination display if exists
          const paginationLinks = document.querySelectorAll('.pagination .pagination-int-item, .pagination .btn');
          paginationLinks.forEach(el => {
            if (el.textContent.trim() == infiniteState.currentPage) {
              el.classList.add('disabled');
            }
          });
        } else {
          infiniteState.hasMore = false;
        }
      } catch (err) {
        console.error('Infinite scroll fetch error:', err);
      } finally {
        infiniteState.loading = false;
        if (foot) {
          foot.innerHTML = infiniteState.hasMore ? '&#9660;' : '&#8212;';
          foot.style.color = 'transparent';
        }
      }
    };

    // Scroll detection - preload before reaching bottom
    const PRELOAD_OFFSET = 500; // pixels before bottom to trigger load

    window.addEventListener("scroll", () => {
      if (!document.querySelector('#main')) return;

      const scrollPosition = window.innerHeight + window.scrollY;
      const pageHeight = document.querySelector('#main').offsetHeight;
      const distanceFromBottom = pageHeight - scrollPosition;

      // Load more when within PRELOAD_OFFSET pixels of bottom
      if (distanceFromBottom < PRELOAD_OFFSET && infiniteState.hasMore && !infiniteState.loading) {
        loadMoreItems();
      }
    });
  }
  // </infinite-scroll>

  // <swipe>
  const swipeRT = {
    xDown: null,
    yDown: null,
    xDiff: null,
    yDiff: null,
    timeDown: null,
    startEl: null
  };
  const swipeOpt = {
    treshold: 20, // 20px
    timeout: 500  // 500ms
  };

  document.addEventListener('touchstart', e => {
    swipeRT.startEl = e.target;
    swipeRT.timeDown = Date.now();
    swipeRT.xDown = e.touches[0].clientX;
    swipeRT.yDown = e.touches[0].clientY;
    swipeRT.xDiff = 0;
    swipeRT.yDiff = 0;
  }, false);

  document.addEventListener('touchmove', e => {
    if (!swipeRT.xDown || !swipeRT.yDown)
      return;
    swipeRT.xDiff = swipeRT.xDown - e.touches[0].clientX;
    swipeRT.yDiff = swipeRT.yDown - e.touches[0].clientY;
  }, false);

  document.addEventListener('touchend', e => {
    if (swipeRT.startEl !== e.target)
      return;

    const timeDiff = Date.now() - swipeRT.timeDown;
    let elem;

    if (Math.abs(swipeRT.xDiff) > Math.abs(swipeRT.yDiff)) {
      if (Math.abs(swipeRT.xDiff) > swipeOpt.treshold && timeDiff < swipeOpt.timeout) {
        if (swipeRT.xDiff > 0) // left
          elem = document.querySelector(".pagination > .next:not(.disabled)");
        else // right
          elem = document.querySelector(".pagination > .prev:not(.disabled)");
      }
    }
    else {
      if (Math.abs(swipeRT.yDiff) > swipeOpt.treshold && timeDiff < swipeOpt.timeout) {
        if (navbar = document.querySelector("nav.navbar") && document.querySelector("div.posts")) {
          if (swipeRT.yDiff > 0 && (window.innerHeight + window.scrollY) >= document.body.offsetHeight) // up
            elem = document.querySelector(".pagination > .next:not(.disabled)");
          else if (swipeRT.yDiff <= 0 && window.scrollY <= 0 && document.querySelector("div.posts")) // down
            elem = document.querySelector(".pagination > .prev:not(.disabled)");
        }
      }
    }

    swipeRT.xDown = null;
    swipeRT.yDown = null;
    swipeRT.timeDown = null;

    if (elem)
      changePage(elem);
  }, false);
  // </swipe>

  // <visualizer>
  if (audioElement = document.querySelector("audio")) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    canvas.width = 1920;
    canvas.height = 1080;

    setTimeout(() => {
      document.querySelector(".v0ck").insertAdjacentElement("afterbegin", canvas);
    }, 400);

    const audioCtx = new AudioContext();
    const analyser = audioCtx.createAnalyser();
    analyser.fftSize = 2048;

    const source = audioCtx.createMediaElementSource(audioElement);
    source.connect(analyser);
    source.connect(audioCtx.destination);

    let data = new Uint8Array(analyser.frequencyBinCount);
    requestAnimationFrame(loopingFunction);

    function loopingFunction() {
      requestAnimationFrame(loopingFunction);
      analyser.getByteFrequencyData(data);
      draw(data);
    }
    function draw(data) {
      data = [...data];
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = getComputedStyle(document.body).getPropertyValue("--accent");
      data.forEach((value, i) => {
        const percent = value / 256;
        const height = (canvas.height * percent / 2) - 40;
        const offset = canvas.height - height - 1;
        const barWidth = canvas.width / analyser.frequencyBinCount;
        ctx.fillRect(i * barWidth, offset, barWidth, height);
      });
    }
    audioElement.onplay = () => {
      audioCtx.resume();
    };
  }
  // </visualizer>

  // <mediakeys>
  if (elem = document.querySelector("#my-video") && "mediaSession" in navigator) {
    const playpauseEvent = () => {
      video[video.paused ? 'play' : 'pause']();
      document.querySelector('.v0ck_overlay').classList[video.paused ? 'remove' : 'add']('v0ck_hidden');
    };
    navigator.mediaSession.setActionHandler('play', playpauseEvent);
    navigator.mediaSession.setActionHandler('pause', playpauseEvent);
    navigator.mediaSession.setActionHandler('stop', playpauseEvent);
    navigator.mediaSession.setActionHandler('previoustrack', () => {
      if (link = document.querySelector(".pagination > .prev:not(.disabled)"))
        changePage(link);
    });
    navigator.mediaSession.setActionHandler('nexttrack', () => {
      if (link = document.querySelector(".pagination > .next:not(.disabled)"))
        changePage(link);
    });
  }
  // </mediakeys>

  // <scroller>

  // <search-overlay>
  const initSearch = () => {
    if (!document.getElementById('search-overlay')) {
      const overlay = document.createElement('div');
      overlay.id = 'search-overlay';
      overlay.innerHTML = `
             <div id="search-close">&times;</div>
             <input type="text" id="search-input" placeholder="Search Tags..." autocomplete="off">
         `;
      document.body.appendChild(overlay);

      const input = document.getElementById('search-input');
      const close = document.getElementById('search-close');
      const btns = document.querySelectorAll('#nav-search-btn, #nav-search-btn-guest');

      const toggleSearch = (show) => {
        if (show) {
          overlay.style.display = 'flex';
          // Force reflow
          overlay.offsetHeight;
          overlay.classList.add('visible');
          input.focus();
        } else {
          overlay.classList.remove('visible');
          setTimeout(() => {
            overlay.style.display = 'none';
          }, 200);
        }
      };

      btns.forEach(btn => btn.addEventListener('click', (e) => {
        e.preventDefault();
        toggleSearch(true);
      }));

      close.addEventListener('click', () => toggleSearch(false));

      // Close on click outside (background)
      overlay.addEventListener('click', (e) => {
        if (e.target === overlay) toggleSearch(false);
      });

      // ESC to close
      document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && overlay.classList.contains('visible')) {
          toggleSearch(false);
        }
        // "k" to open
        if (e.key === 'k' && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && !overlay.classList.contains('visible')) {
          e.preventDefault();
          toggleSearch(true);
        }
      });

      input.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
          const val = input.value.trim();
          if (val) {
            window.location.href = `/tag/${encodeURIComponent(val)}`;
          }
        }
      });
    }
  };
  initSearch();
  // </search-overlay>

  // </scroller>
})();


// disable default scroll event when mouse is on content div
// this is useful for items that have a lot of tags for example: 12536
const targetSelector = '.content';
let isMouseOver = true;

function isPageScrollable() {
  return document.documentElement.scrollHeight > document.documentElement.clientHeight;
}

function onWheel(e) {
  if (isMouseOver && isPageScrollable()) {
    e.preventDefault();
  }
}

function init() {
  const el = document.querySelector(targetSelector);
  if (!el) return;
  el.addEventListener('mouseenter', () => isMouseOver = true);
  el.addEventListener('mouseleave', () => isMouseOver = false);
  window.addEventListener('wheel', onWheel, { passive: false });
}

window.addEventListener('load', init);

const sbtForm = document.getElementById('sbtForm');
if (sbtForm) {
  sbtForm.addEventListener('submit', (e) => {
    e.preventDefault();
    const input = document.getElementById('sbtInput').value.trim();
    if (input) {
      window.location.href = `/tag/${encodeURIComponent(input)}`;
    }
  });
}
