import { useState, useCallback } from 'react';

/**
 * PDF Export — block-based strategy.
 *
 * Each section is broken into atomic sub-blocks that are never split across
 * pages. Dark sections with Framer Motion animations require special handling:
 * we scroll every section into view to trigger `whileInView`, then force all
 * inline opacity/transform to their final state before html2canvas captures.
 */

function isDarkSection(section: HTMLElement): boolean {
  const bg = window.getComputedStyle(section).backgroundColor;
  if (!bg || bg === 'rgba(0, 0, 0, 0)' || bg === 'transparent') return false;
  // Parse rgb(r, g, b) — dark if luminance is low
  const match = bg.match(/(\d+),\s*(\d+),\s*(\d+)/);
  if (!match) return section.classList.contains('bg-[#0A1128]');
  const [, r, g, b] = match.map(Number);
  return (r * 0.299 + g * 0.587 + b * 0.114) < 50;
}

function collectSubBlocks(section: HTMLElement): HTMLElement[] {
  // Dark sections should be captured whole — sub-blocks would lose the dark background
  if (isDarkSection(section)) return [section];

  if (section.offsetHeight <= 900) return [section];

  const children = Array.from(section.children) as HTMLElement[];
  if (children.length <= 1) return [section];

  const blocks: HTMLElement[] = [];
  for (const child of children) {
    if (child.offsetHeight === 0 || child.offsetWidth === 0) continue;
    blocks.push(child);
  }
  return blocks.length > 0 ? blocks : [section];
}

/**
 * Scroll through every section to trigger all `whileInView` animations,
 * then wait for them to settle. This ensures Framer Motion has applied
 * its final inline styles before we snapshot.
 */
async function triggerAllAnimations(contentEl: HTMLElement): Promise<void> {
  const sections = Array.from(contentEl.children) as HTMLElement[];

  for (const section of sections) {
    section.scrollIntoView({ behavior: 'instant' as ScrollBehavior });
    // Give framer-motion time to observe intersection and apply styles
    await new Promise((r) => setTimeout(r, 80));

    // Also scroll sub-children into view for nested whileInView
    const motionChildren = section.querySelectorAll('[style]');
    for (let i = 0; i < Math.min(motionChildren.length, 20); i++) {
      (motionChildren[i] as HTMLElement).scrollIntoView({ behavior: 'instant' as ScrollBehavior });
      await new Promise((r) => setTimeout(r, 30));
    }
  }

  // Scroll back to top and let everything settle
  window.scrollTo(0, 0);
  await new Promise((r) => setTimeout(r, 200));
}

/**
 * Force ALL elements to be fully visible — opacity 1, no transforms.
 * This catches any remaining elements that whileInView didn't reach.
 */
function forceVisible(contentEl: HTMLElement): (() => void) {
  document.documentElement.style.setProperty('--motion-duration', '0s');

  const saved: { el: HTMLElement; cssText: string }[] = [];

  contentEl.querySelectorAll('*').forEach((node) => {
    const el = node as HTMLElement;
    const s = el.style;

    // Check both inline and computed
    const needsFix =
      (s.opacity !== '' && s.opacity !== '1') ||
      (s.transform !== '' && s.transform !== 'none') ||
      s.visibility === 'hidden';

    if (needsFix) {
      saved.push({ el, cssText: s.cssText });
      s.opacity = '1';
      s.transform = 'none';
      s.visibility = 'visible';
    }
  });

  // Second pass: catch computed opacity < 1 (motion might set via class)
  contentEl.querySelectorAll('*').forEach((node) => {
    const el = node as HTMLElement;
    const computed = window.getComputedStyle(el);
    if (parseFloat(computed.opacity) < 0.99) {
      if (!saved.find((s) => s.el === el)) {
        saved.push({ el, cssText: el.style.cssText });
      }
      el.style.opacity = '1';
      el.style.transform = 'none';
    }
  });

  return () => {
    saved.forEach(({ el, cssText }) => {
      el.style.cssText = cssText;
    });
    document.documentElement.style.removeProperty('--motion-duration');
  };
}

/**
 * CSS overrides for export: unwrap overflow, prevent clipping.
 */
function addExportCSS(): (() => void) {
  const style = document.createElement('style');
  style.id = 'pdf-export-overrides';
  style.textContent = `
    [data-report-content] .overflow-x-auto,
    [data-plan-content] .overflow-x-auto {
      overflow: visible !important;
      flex-wrap: wrap !important;
    }
    [data-report-content] .scrollbar-thin,
    [data-plan-content] .scrollbar-thin {
      overflow: visible !important;
    }
    [data-report-content] .shrink-0,
    [data-plan-content] .shrink-0 {
      flex-shrink: 1 !important;
      min-width: 0 !important;
    }
  `;
  document.head.appendChild(style);
  return () => style.remove();
}

export function useExportPDF() {
  const [isExporting, setIsExporting] = useState(false);

  const exportPDF = useCallback(async (filename = 'INFINITH_Marketing_Intelligence_Report') => {
    setIsExporting(true);

    try {
      const [{ default: html2canvas }, { jsPDF }] = await Promise.all([
        import('html2canvas-pro'),
        import('jspdf'),
      ]);

      const contentEl =
        (document.querySelector('[data-report-content]') as HTMLElement) ||
        (document.querySelector('[data-plan-content]') as HTMLElement);
      if (!contentEl) throw new Error('Report content element not found');

      // Step 1: Scroll through all sections to trigger whileInView animations
      await triggerAllAnimations(contentEl);

      // Step 2: Force everything visible (catch stragglers)
      const restoreVisible = forceVisible(contentEl);

      // Step 3: CSS overrides
      const restoreCSS = addExportCSS();

      // Step 4: Hide UI elements
      const hideSelectors = [
        '[data-report-nav]',
        '[data-plan-nav]',
        'nav',
        '[data-cta-card]',
        '[data-no-print]',
      ];
      const hiddenEls: { el: HTMLElement; display: string }[] = [];
      hideSelectors.forEach((sel) => {
        document.querySelectorAll(sel).forEach((el) => {
          const htmlEl = el as HTMLElement;
          hiddenEls.push({ el: htmlEl, display: htmlEl.style.display });
          htmlEl.style.display = 'none';
        });
      });

      await new Promise((r) => setTimeout(r, 150));

      // Step 5: PDF generation
      const pdf = new jsPDF('p', 'mm', 'a4');
      const pageWidth = 210;
      const pageHeight = 297;
      const margin = 8;
      const usableWidth = pageWidth - margin * 2;
      const footerSpace = 10;
      const maxContentY = pageHeight - margin - footerSpace;
      let currentY = margin;

      const sections = Array.from(contentEl.children) as HTMLElement[];

      for (const section of sections) {
        if (section.offsetHeight === 0 || section.offsetWidth === 0) continue;
        if (window.getComputedStyle(section).display === 'none') continue;

        const blocks = collectSubBlocks(section);

        for (const block of blocks) {
          if (block.offsetHeight === 0) continue;

          const canvas = await html2canvas(block, {
            scale: 2,
            useCORS: true,
            logging: false,
            backgroundColor: null,
            windowWidth: 1280,
            removeContainer: true,
          });

          const blockHeightMM = (canvas.height * usableWidth) / canvas.width;

          // New page if block doesn't fit
          if (currentY + blockHeightMM > maxContentY && currentY > margin + 5) {
            pdf.addPage();
            currentY = margin;
          }

          // Tall block: slice across pages
          if (blockHeightMM > maxContentY - margin) {
            const pxPerMM = canvas.width / usableWidth;
            let srcY = 0;
            let remainPx = canvas.height;
            let isFirst = true;

            while (remainPx > 0) {
              if (!isFirst) { pdf.addPage(); currentY = margin; }
              isFirst = false;

              const availPx = (maxContentY - currentY) * pxPerMM;
              const sliceH = Math.min(remainPx, availPx);

              const sliceCanvas = document.createElement('canvas');
              sliceCanvas.width = canvas.width;
              sliceCanvas.height = Math.ceil(sliceH);
              const ctx = sliceCanvas.getContext('2d');
              if (ctx) {
                ctx.drawImage(canvas, 0, srcY, canvas.width, Math.ceil(sliceH), 0, 0, canvas.width, Math.ceil(sliceH));
              }

              const sliceMM = sliceH / pxPerMM;
              pdf.addImage(sliceCanvas.toDataURL('image/jpeg', 0.9), 'JPEG', margin, currentY, usableWidth, sliceMM);
              currentY += sliceMM;
              srcY += sliceH;
              remainPx -= sliceH;
            }
          } else {
            pdf.addImage(canvas.toDataURL('image/jpeg', 0.9), 'JPEG', margin, currentY, usableWidth, blockHeightMM);
            currentY += blockHeightMM;
          }
        }

        currentY += 2; // Gap between sections
      }

      // Step 6: Restore
      hiddenEls.forEach(({ el, display }) => { el.style.display = display; });
      restoreCSS();
      restoreVisible();

      // Step 7: Footers
      const totalPages = pdf.getNumberOfPages();
      const footerLabel = filename.includes('Plan')
        ? 'INFINITH Marketing Plan'
        : 'INFINITH Marketing Intelligence Report';
      for (let i = 1; i <= totalPages; i++) {
        pdf.setPage(i);
        pdf.setFontSize(7);
        pdf.setTextColor(180);
        pdf.text(`${footerLabel}  |  Page ${i} / ${totalPages}`, pageWidth / 2, pageHeight - 5, { align: 'center' });
      }

      pdf.save(`${filename}.pdf`);
    } catch (err) {
      console.error('PDF export failed:', err);
    } finally {
      setIsExporting(false);
    }
  }, []);

  return { exportPDF, isExporting };
}
