<script setup>
import PagedJsWrapper from './components/PagedJsWrapper.vue';
import EditorPanel from './components/editor/EditorPanel.vue';
import ElementPopup from './components/ElementPopup.vue';
import PagePopup from './components/PagePopup.vue';
import PreviewLoader from './components/PreviewLoader.vue';
import { onMounted, ref, watch, computed, provide } from 'vue';
import { useStylesheetStore } from './stores/stylesheet';
import Coloris from '@melloware/coloris';

const stylesheetStore = useStylesheetStore();
const previewFrame1 = ref(null);
const previewFrame2 = ref(null);
const elementPopup = ref(null);
const pagePopup = ref(null);
const activeTab = ref('');

provide('activeTab', activeTab);

// Page interaction state
const hoveredPage = ref(null);
const EDGE_THRESHOLD = 30; // px from edge to trigger hover

let savedScrollPercentage = 0;
const currentFrameIndex = ref(1); // 1 or 2, which iframe is currently visible
const isTransitioning = ref(false);

const activeFrame = computed(() => {
  return currentFrameIndex.value === 1
    ? previewFrame1.value
    : previewFrame2.value;
});

// Check if mouse position is near the edges of a page element
const isNearPageEdge = (pageElement, mouseX, mouseY) => {
  const rect = pageElement.getBoundingClientRect();

  const nearLeft = mouseX >= rect.left && mouseX <= rect.left + EDGE_THRESHOLD;
  const nearRight = mouseX >= rect.right - EDGE_THRESHOLD && mouseX <= rect.right;
  const nearTop = mouseY >= rect.top && mouseY <= rect.top + EDGE_THRESHOLD;
  const nearBottom = mouseY >= rect.bottom - EDGE_THRESHOLD && mouseY <= rect.bottom;

  const inHorizontalRange = mouseY >= rect.top && mouseY <= rect.bottom;
  const inVerticalRange = mouseX >= rect.left && mouseX <= rect.right;

  return (
    (nearLeft && inHorizontalRange) ||
    (nearRight && inHorizontalRange) ||
    (nearTop && inVerticalRange) ||
    (nearBottom && inVerticalRange)
  );
};

// Handle mouse movement in iframe
const handleIframeMouseMove = (event) => {
  const pages = event.target.ownerDocument.querySelectorAll('.pagedjs_page');
  let foundPage = null;

  for (const page of pages) {
    if (isNearPageEdge(page, event.clientX, event.clientY)) {
      foundPage = page;
      break;
    }
  }

  // Update hover state
  if (foundPage !== hoveredPage.value) {
    // Remove highlight from previous page
    if (hoveredPage.value) {
      hoveredPage.value.style.outline = '';
    }

    // Add highlight to new page
    if (foundPage) {
      foundPage.style.outline = '2px solid rgba(97, 175, 239, 0.3)';
    }

    hoveredPage.value = foundPage;
  }
};

// Handle click in iframe
const handleIframeClick = (event) => {
  const element = event.target;

  // Check if clicking near a page edge
  if (hoveredPage.value) {
    event.stopPropagation();
    pagePopup.value.open(hoveredPage.value, event);
    elementPopup.value.close();
    return;
  }

  // Otherwise handle as element click
  if (element.tagName === 'BODY' || element.tagName === 'HTML') {
    elementPopup.value.close();
    pagePopup.value.close();
    return;
  }

  elementPopup.value.handleIframeClick(event);
  pagePopup.value.close();
};

const renderPreview = async (shouldReloadFromFile = false) => {
  if (isTransitioning.value) return;
  isTransitioning.value = true;

  // Determine which iframe is currently visible and which to render to
  const visibleFrame =
    currentFrameIndex.value === 1 ? previewFrame1.value : previewFrame2.value;
  const hiddenFrame =
    currentFrameIndex.value === 1 ? previewFrame2.value : previewFrame1.value;

  if (!hiddenFrame) {
    isTransitioning.value = false;
    return;
  }

  // Save scroll position from visible frame
  if (
    visibleFrame &&
    visibleFrame.contentWindow &&
    visibleFrame.contentDocument
  ) {
    const scrollTop = visibleFrame.contentWindow.scrollY || 0;
    const scrollHeight =
      visibleFrame.contentDocument.documentElement.scrollHeight;
    const clientHeight = visibleFrame.contentWindow.innerHeight;
    const maxScroll = scrollHeight - clientHeight;

    savedScrollPercentage = maxScroll > 0 ? scrollTop / maxScroll : 0;
  }

  if (shouldReloadFromFile || !stylesheetStore.content) {
    await stylesheetStore.loadStylesheet();
  }

  // Render to the hidden frame
  hiddenFrame.srcdoc = `
    <!DOCTYPE html>
    <html>
    <head>
      <link rel="stylesheet" href="/assets/css/pagedjs-interface.css">
      <style id="dynamic-styles">${stylesheetStore.content}</style>
      <script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"><\/script>
    </head>
    <body>${document.getElementById('content-source').innerHTML}</body>
    </html>
  `;

  hiddenFrame.onload = () => {
    // Add event listeners for page and element interactions
    hiddenFrame.contentDocument.addEventListener('mousemove', handleIframeMouseMove);
    hiddenFrame.contentDocument.addEventListener('click', handleIframeClick);

    // Close Coloris when clicking in the iframe
    hiddenFrame.contentDocument.addEventListener('click', () => {
      Coloris.close();
    });

    // Wait for PagedJS to finish rendering
    setTimeout(() => {
      // Restore scroll position
      const scrollHeight =
        hiddenFrame.contentDocument.documentElement.scrollHeight;
      const clientHeight = hiddenFrame.contentWindow.innerHeight;
      const maxScroll = scrollHeight - clientHeight;
      const targetScroll = savedScrollPercentage * maxScroll;

      hiddenFrame.contentWindow.scrollTo(0, targetScroll);

      // Start crossfade transition
      setTimeout(() => {
        // Make hidden frame visible (it's already behind)
        hiddenFrame.style.opacity = '1';
        hiddenFrame.style.zIndex = '1';

        // Fade out visible frame
        if (visibleFrame) {
          visibleFrame.style.opacity = '0';
        }

        // After fade completes, swap the frames
        setTimeout(() => {
          if (visibleFrame) {
            visibleFrame.style.zIndex = '0';
          }

          // Swap current frame
          currentFrameIndex.value = currentFrameIndex.value === 1 ? 2 : 1;
          isTransitioning.value = false;
        }, 200); // Match CSS transition duration
      }, 50); // Small delay to ensure scroll is set
    }, 200); // Wait for PagedJS
  };
};

watch(
  () => stylesheetStore.content,
  () => {
    renderPreview();
  }
);

onMounted(() => renderPreview(true));
</script>

<template>
  <div id="content-source" style="display: none">
    <PagedJsWrapper />
  </div>

  <EditorPanel />

  <iframe
    ref="previewFrame1"
    class="preview-frame"
    :class="{ shifted: activeTab.length > 0 }"
  ></iframe>
  <iframe
    ref="previewFrame2"
    class="preview-frame"
    :class="{ shifted: activeTab.length > 0 }"
  ></iframe>

  <PreviewLoader :isLoading="isTransitioning" :shifted="activeTab.length > 0" />

  <ElementPopup ref="elementPopup" :iframeRef="activeFrame" />
  <PagePopup ref="pagePopup" :iframeRef="activeFrame" />
</template>

<style>
.preview-frame {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  border: none;
  margin-left: 0;
  transform: scale(1) translateY(0);
  height: 100vh;
  transition: all 0.2s ease-in-out var(--curve);
}

.preview-frame.shifted {
  margin-left: 17.55rem;
  transform: scale(0.65) translateY(-40vh);
  height: 155vh;
}

.preview-frame:nth-of-type(1) {
  z-index: 1;
  opacity: 1;
}

.preview-frame:nth-of-type(2) {
  z-index: 0;
  opacity: 0;
}
</style>
