
(function () {
  const modal = document.getElementById('preview-modal');
  if (!modal) { window.__filehubReady = false; return; }

  const body = document.body;
  const dialog = document.getElementById('preview-dialog');
  const title = document.getElementById('preview-title');
  const meta = document.getElementById('preview-meta');
  const empty = document.getElementById('preview-empty');
  const imageStage = document.getElementById('preview-image-stage');
  const image = document.getElementById('preview-image');
  const imgViewer = document.getElementById('img-viewer');
  const imgCanvas = document.getElementById('img-viewer-canvas');
  const zoomLabel = document.getElementById('img-zoom-label');
  const videoStage = document.getElementById('preview-video-stage');
  const video = document.getElementById('preview-video');
  const audioStage = document.getElementById('preview-audio-stage');
  const audio = document.getElementById('preview-audio');
  const iframeStage = document.getElementById('preview-iframe-stage');
  const iframe = document.getElementById('preview-iframe');
  const markdownStage = document.getElementById('preview-markdown-stage');
  const markdown = document.getElementById('preview-markdown');
  const codeStage = document.getElementById('preview-code-stage');
  const code = document.getElementById('preview-code');
  const plainStage = document.getElementById('preview-plain-stage');
  const plain = document.getElementById('preview-plain');
  const closeButtons = modal.querySelectorAll('[data-preview-close]');
  const previewButtons = document.querySelectorAll('[data-preview-trigger]');
  const stages = [imageStage, videoStage, audioStage, iframeStage, markdownStage, codeStage, plainStage];

  // ── Image viewer state ──
  let imgScale = 1, imgRotate = 0, imgPanX = 0, imgPanY = 0;
  let imgNaturalW = 0, imgNaturalH = 0;
  let isDragging = false, dragStartX = 0, dragStartY = 0, panStartX = 0, panStartY = 0;

  function escapeHtml(text) {
    return String(text)
      .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
  }

  function showEmpty(message, isError) {
    empty.textContent = message;
    empty.classList.remove('hidden');
    empty.classList.toggle('preview-error', Boolean(isError));
  }

  function hideEmpty() {
    empty.classList.add('hidden');
    empty.classList.remove('preview-error');
  }

  function resetMedia() {
    image.removeAttribute('src');
    image.alt = '';
    imgScale = 1; imgRotate = 0; imgPanX = 0; imgPanY = 0;
    applyImageTransform();
    video.pause(); video.removeAttribute('src'); video.load();
    audio.pause(); audio.removeAttribute('src'); audio.load();
    iframe.removeAttribute('src');
    markdown.innerHTML = '';
    code.textContent = '';
    plain.textContent = '';
    showEmpty('加载中…', false);
    stages.forEach(function (s) { s.classList.remove('active'); });
  }

  function showStage(stage) {
    stages.forEach(function (s) { s.classList.toggle('active', s === stage); });
    hideEmpty();
  }

  function openModal() {
    modal.classList.add('open');
    modal.setAttribute('aria-hidden', 'false');
    body.classList.add('modal-open');
  }

  function closeModal() {
    modal.classList.remove('open');
    modal.setAttribute('aria-hidden', 'true');
    body.classList.remove('modal-open');
    isMaximized = false;
    dialog.classList.remove('maximized');
    if (fullscreenBtn) fullscreenBtn.textContent = '⛶';
    resetMedia();
  }

  // ── Image transform ──
  function applyImageTransform() {
    var s = Math.max(imgScale, 0.05);
    image.style.transform = 'translate(' + imgPanX + 'px,' + imgPanY + 'px) scale(' + s + ') rotate(' + imgRotate + 'deg)';
    zoomLabel.textContent = Math.round(s * 100) + '%';
  }

  function fitImage() {
    if (!imgNaturalW) return;
    var cw = imgCanvas.clientWidth - 40;
    var ch = imgCanvas.clientHeight - 40;
    var rad = Math.abs(imgRotate % 180);
    var iw = rad > 45 && rad < 135 ? imgNaturalH : imgNaturalW;
    var ih = rad > 45 && rad < 135 ? imgNaturalW : imgNaturalH;
    imgScale = Math.min(cw / iw, ch / ih, 1);
    imgPanX = 0; imgPanY = 0;
    applyImageTransform();
  }

  function resetImage() {
    imgScale = 1; imgRotate = 0; imgPanX = 0; imgPanY = 0;
    applyImageTransform();
  }

  // ── Zoom ──
  imgCanvas.addEventListener('wheel', function (e) {
    if (!image.src) return;
    e.preventDefault();
    var rect = imgCanvas.getBoundingClientRect();
    var mx = e.clientX - rect.left - rect.width / 2;
    var my = e.clientY - rect.top - rect.height / 2;
    var oldScale = imgScale;
    var delta = e.deltaY < 0 ? 1.15 : 0.87;
    imgScale = Math.max(0.1, Math.min(10, imgScale * delta));
    imgPanX = mx + (imgPanX - mx) * (imgScale / oldScale);
    imgPanY = my + (imgPanY - my) * (imgScale / oldScale);
    applyImageTransform();
  }, { passive: false });

  // ── Drag/Pan ──
  imgCanvas.addEventListener('pointerdown', function (e) {
    if (!image.src) return;
    isDragging = true;
    dragStartX = e.clientX;
    dragStartY = e.clientY;
    panStartX = imgPanX;
    panStartY = imgPanY;
    imgCanvas.setPointerCapture(e.pointerId);
  });

  imgCanvas.addEventListener('pointermove', function (e) {
    if (!isDragging) return;
    imgPanX = panStartX + (e.clientX - dragStartX);
    imgPanY = panStartY + (e.clientY - dragStartY);
    applyImageTransform();
  });

  imgCanvas.addEventListener('pointerup', function () { isDragging = false; });
  imgCanvas.addEventListener('pointerleave', function () { isDragging = false; });

  // ── Toolbar ──
  imgViewer.addEventListener('click', function (e) {
    var btn = e.target.closest('button[data-action]');
    if (!btn) return;
    var action = btn.dataset.action;
    if (action === 'zoom-in') { imgScale = Math.min(10, imgScale * 1.3); applyImageTransform(); }
    if (action === 'zoom-out') { imgScale = Math.max(0.1, imgScale * 0.77); applyImageTransform(); }
    if (action === 'rotate-left') { imgRotate -= 90; fitImage(); }
    if (action === 'rotate-right') { imgRotate += 90; fitImage(); }
    if (action === 'fit') { fitImage(); }
    if (action === 'reset') { resetImage(); }
  });

  // ── Keyboard ──
  document.addEventListener('keydown', function (e) {
    if (!modal.classList.contains('open')) return;
    if (!imageStage.classList.contains('active')) return;
    if (e.key === '+' || e.key === '=') { e.preventDefault(); imgScale = Math.min(10, imgScale * 1.2); applyImageTransform(); }
    if (e.key === '-') { e.preventDefault(); imgScale = Math.max(0.1, imgScale * 0.83); applyImageTransform(); }
    if (e.key === 'r') { e.preventDefault(); imgRotate += 90; fitImage(); }
    if (e.key === 'f') { e.preventDefault(); fitImage(); }
    if (e.key === '0') { e.preventDefault(); resetImage(); }
    if (e.key === 'ArrowLeft')  { imgPanX -= 30; applyImageTransform(); }
    if (e.key === 'ArrowRight') { imgPanX += 30; applyImageTransform(); }
    if (e.key === 'ArrowUp')    { imgPanY -= 30; applyImageTransform(); }
    if (e.key === 'ArrowDown')  { imgPanY += 30; applyImageTransform(); }
  });

  // ── Double-click to fit/1:1 ──
  imgCanvas.addEventListener('dblclick', function () {
    if (!image.src) return;
    if (Math.abs(imgScale - 1) < 0.01) { fitImage(); }
    else { resetImage(); }
  });

  // ── Maximize (web fullscreen) ──
  var fullscreenBtn = document.getElementById('preview-fullscreen-btn');
  var isMaximized = false;
  function toggleMaximize() {
    isMaximized = !isMaximized;
    dialog.classList.toggle('maximized', isMaximized);
    if (fullscreenBtn) {
      fullscreenBtn.textContent = isMaximized ? '🗗' : '⛶';
    }
  }
  if (fullscreenBtn) {
    fullscreenBtn.addEventListener('click', toggleMaximize);
  }

  // ── Markdown renderer (kept for fallback) ──
  function renderInline(text) {
    return escapeHtml(text)
      .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
      .replace(/\*(.+?)\*/g, '<em>$1</em>')
      .replace(/`([^`]+)`/g, '<code>$1</code>')
      .replace(/\[(.+?)\]\((https?:[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noreferrer">$1</a>');
  }

  function renderMarkdown(source) {
    const lines = String(source).replace(/\r\n?/g, '\n').split('\n');
    const parts = [];
    let inCode = false, codeLines = [], listType = null, listItems = [], paragraph = [];
    function flushParagraph() {
      if (!paragraph.length) return;
      parts.push('<p>' + renderInline(paragraph.join('<br>')) + '</p>');
      paragraph = [];
    }
    function flushList() {
      if (!listItems.length || !listType) return;
      parts.push('<' + listType + '>' + listItems.map(function (item) {
        return '<li>' + renderInline(item) + '</li>';
      }).join('') + '</' + listType + '>');
      listItems = []; listType = null;
    }
    function flushCode() {
      if (!inCode) return;
      parts.push('<pre><code>' + escapeHtml(codeLines.join('\n')) + '</code></pre>');
      codeLines = []; inCode = false;
    }
    lines.forEach(function (line) {
      if (line.trim().startsWith('```')) { flushParagraph(); flushList(); if (inCode) flushCode(); else { inCode = true; codeLines = []; } return; }
      if (inCode) { codeLines.push(line); return; }
      if (!line.trim()) { flushParagraph(); flushList(); return; }
      if (line.startsWith('# ')) { flushParagraph(); flushList(); parts.push('<h1>' + renderInline(line.slice(2).trim()) + '</h1>'); return; }
      if (line.startsWith('## ')) { flushParagraph(); flushList(); parts.push('<h2>' + renderInline(line.slice(3).trim()) + '</h2>'); return; }
      if (line.startsWith('### ')) { flushParagraph(); flushList(); parts.push('<h3>' + renderInline(line.slice(4).trim()) + '</h3>'); return; }
      if (line.startsWith('> ')) { flushParagraph(); flushList(); parts.push('<blockquote>' + renderInline(line.slice(2).trim()) + '</blockquote>'); return; }
      if (line.startsWith('- ')) { flushParagraph(); if (listType && listType !== 'ul') flushList(); listType = 'ul'; listItems.push(line.slice(2).trim()); return; }
      if (/^\d+\.\s/.test(line)) { flushParagraph(); if (listType && listType !== 'ol') flushList(); listType = 'ol'; listItems.push(line.replace(/^\d+\.\s/, '').trim()); return; }
      flushList();
      paragraph.push(line.trim());
    });
    flushParagraph(); flushList(); flushCode();
    return parts.join('');
  }

  async function openPreview(button) {
    resetMedia();
    const url = button.dataset.previewUrl || '';
    const kind = button.dataset.previewKind || 'unsupported';
    title.textContent = button.dataset.previewName || '预览';
    meta.textContent = button.dataset.previewMeta || '';
    openModal();

    try {
      if (kind === 'image') {
        image.onload = function () {
          imgNaturalW = image.naturalWidth;
          imgNaturalH = image.naturalHeight;
          fitImage();
        };
        image.src = url;
        image.alt = button.dataset.previewName || '';
        showStage(imageStage);
        return;
      }
      if (kind === 'video') { video.src = url; showStage(videoStage); return; }
      if (kind === 'audio') { audio.src = url; showStage(audioStage); return; }
      if (kind === 'pdf') { iframe.src = url; showStage(iframeStage); return; }
      if (kind === 'markdown' || kind === 'code' || kind === 'plain') {
        const response = await fetch(url, { credentials: 'same-origin' });
        if (!response.ok) throw new Error('加载失败');
        const text = await response.text();
        if (kind === 'markdown') { markdown.innerHTML = text; showStage(markdownStage); return; }
        if (kind === 'code') { code.textContent = text; showStage(codeStage); return; }
        plain.textContent = text; showStage(plainStage); return;
      }
      showEmpty('当前文件暂不支持弹窗预览，请直接下载查看。', false);
    } catch (error) {
      showEmpty('预览加载失败，请稍后重试或直接下载文件。', true);
    }
  }

  window.filehubOpenPreview = openPreview;

  // ── Password gate ──
  var ACCESS_PASSWORD = '5210';
  var pwdOverlay = document.getElementById('pwd-overlay');
  var pwdInputsEl = document.getElementById('pwd-inputs');
  var pwdDigits = pwdInputsEl.querySelectorAll('.pwd-digit');
  var pwdError = document.getElementById('pwd-error');
  var pwdAuthenticated = false;
  var pwdPendingButton = null;

  function openPwdOverlay(button) {
    pwdPendingButton = button;
    pwdOverlay.classList.add('open');
    pwdOverlay.setAttribute('aria-hidden', 'false');
    pwdError.classList.add('hidden');
    pwdInputsEl.classList.remove('shaking');
    pwdDigits.forEach(function (d) { d.value = ''; d.classList.remove('has-value'); });
    setTimeout(function () { pwdDigits[0].focus(); }, 80);
    body.classList.add('modal-open');
  }

  function closePwdOverlay() {
    pwdOverlay.classList.remove('open');
    pwdOverlay.setAttribute('aria-hidden', 'true');
    pwdPendingButton = null;
    pwdDigits.forEach(function (d) { d.value = ''; d.classList.remove('has-value'); });
    pwdError.classList.add('hidden');
    pwdInputsEl.classList.remove('shaking');
    body.classList.remove('modal-open');
  }

  function getEnteredPassword() {
    var val = '';
    pwdDigits.forEach(function (d) { val += d.value; });
    return val;
  }

  function verifyPassword() {
    var entered = getEnteredPassword();
    if (entered === ACCESS_PASSWORD) {
      pwdAuthenticated = true;
      var btn = pwdPendingButton;
      closePwdOverlay();
      if (btn) { openPreview(btn); }
    } else {
      pwdError.classList.remove('hidden');
      pwdDigits.forEach(function (d) { d.value = ''; d.classList.remove('has-value'); });
      pwdInputsEl.classList.remove('shaking');
      void pwdInputsEl.offsetWidth; // reflow
      pwdInputsEl.classList.add('shaking');
      pwdDigits[0].focus();
    }
  }

  // Wire up 4-digit inputs
  pwdDigits.forEach(function (input, idx) {
    input.addEventListener('input', function () {
      var v = input.value.replace(/[^0-9]/g, '');
      input.value = v.slice(0, 1);
      if (v) {
        input.classList.add('has-value');
        if (idx < 3) {
          pwdDigits[idx + 1].focus();
        } else {
          // All 4 digits entered — verify
          verifyPassword();
        }
      } else {
        input.classList.remove('has-value');
      }
    });
    input.addEventListener('keydown', function (e) {
      if (e.key === 'Backspace' && input.value === '' && idx > 0) {
        pwdDigits[idx - 1].focus();
      }
    });
    // Allow paste across inputs
    input.addEventListener('paste', function (e) {
      e.preventDefault();
      var pasted = (e.clipboardData || window.clipboardData).getData('text');
      var digits = pasted.replace(/[^0-9]/g, '').slice(0, 4).split('');
      if (digits.length === 4) {
        digits.forEach(function (d, i) {
          pwdDigits[i].value = d;
          pwdDigits[i].classList.add('has-value');
        });
        verifyPassword();
      }
    });
  });

  // Click outside dialog to close
  pwdOverlay.addEventListener('click', function (e) {
    if (e.target === pwdOverlay) { closePwdOverlay(); }
  });

  // Escape key closes password overlay
  document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape' && pwdOverlay.classList.contains('open')) {
      closePwdOverlay();
    }
  });

  // ── Preview trigger with password gate ──
  function handleGatedClick(element, action) {
    return function (event) {
      event.preventDefault();
      if (!pwdAuthenticated) {
        pwdPendingAction = action;
        pwdPendingElement = element;
        openPwdOverlay(element);
      } else {
        action(element);
      }
    };
  }

  // When password ok, dispatch to correct action
  var pwdPendingAction = null;
  var pwdPendingElement = null;

  function dispatchPendingAction() {
    if (pwdPendingAction && pwdPendingElement) {
      var action = pwdPendingAction;
      var elem = pwdPendingElement;
      pwdPendingAction = null;
      pwdPendingElement = null;
      action(elem);
    }
  }

  // Override close to also clear pending
  var _closePwdOverlay = closePwdOverlay;
  closePwdOverlay = function () {
    pwdPendingAction = null;
    pwdPendingElement = null;
    _closePwdOverlay();
  };

  function doDownload(element) {
    var url = element.getAttribute('data-download-url');
    if (url) {
      window.location.href = url;
    } else if (element.href) {
      window.location.href = element.href;
    }
  }

  // Preview buttons
  previewButtons.forEach(function (button) {
    button.addEventListener('click', handleGatedClick(button, openPreview));
  });

  // File name links (previewable)
  var nameLinks = document.querySelectorAll('.item-link[data-preview-trigger]');
  nameLinks.forEach(function (link) {
    link.addEventListener('click', handleGatedClick(link, openPreview));
  });

  // File name links (non-previewable) — do nothing
  var deadLinks = document.querySelectorAll('.item-link[href="#"]:not([data-preview-trigger])');
  deadLinks.forEach(function (link) {
    link.addEventListener('click', function (event) {
      event.preventDefault();
    });
  });

  // Download links
  var downloadLinks = document.querySelectorAll('.download[data-download-trigger]');
  downloadLinks.forEach(function (link) {
    link.addEventListener('click', handleGatedClick(link, doDownload));
  });

  // Update verifyPassword to handle both preview and download, plus 4-digit UX
  var _verifyPassword = verifyPassword;
  verifyPassword = function () {
    var digits = [];
    pwdDigits.forEach(function (d) { digits.push(d.value); });
    var entered = digits.join('');
    if (entered === ACCESS_PASSWORD) {
      pwdAuthenticated = true;
      var elem = pwdPendingElement;
      var action = pwdPendingAction;
      closePwdOverlay();
      if (elem && action) {
        action(elem);
      }
    } else {
      pwdError.classList.remove('hidden');
      pwdDigits.forEach(function (d) { d.value = ''; d.classList.remove('has-value'); });
      pwdDigits[0].focus();
      pwdContainer.classList.add('shaking');
      setTimeout(function () { pwdContainer.classList.remove('shaking'); }, 500);
    }
  };

  document.addEventListener('click', function (event) {
    if (event.target === modal || event.target.closest('[data-preview-close]')) {
      closeModal();
    }
  });

  document.addEventListener('keydown', function (event) {
    if (event.key === 'Escape' && modal.classList.contains('open')) {
      const activeImg = imageStage.classList.contains('active');
      if (activeImg && (imgScale !== 1 || imgRotate !== 0)) {
        resetImage();
      } else {
        closeModal();
      }
    }
    if ((event.key === 'F' || event.key === 'f' && event.shiftKey) && modal.classList.contains('open')) {
      event.preventDefault();
      toggleMaximize();
    }
  });

  closeButtons.forEach(function (button) {
    button.addEventListener('click', closeModal);
  });

  window.__filehubReady = true;
})();
