import React, { useMemo, useRef, useEffect } from 'react';
import { Frame, Element, useEditor } from '@craftjs/core';
import { Container } from '../components/layout/Container';
import { usePages } from '../state/PageContext';
import { DeviceMode } from '../types';
import { DEVICE_WIDTHS } from '../constants/presets';
import { exportBodyHtml } from '../utils/html-export';
import { useIsMobile } from '../hooks/useIsMobile';
import { useMobileChrome } from '../state/MobileChromeContext';

interface CanvasProps {
  device: DeviceMode;
  /** Item 10: when false, applies `.guides-off` to hide the dashed drop-target guides. */
  showGuides: boolean;
}

/**
 * Renders the actual header/footer content from the Craft.js state as a
 * non-interactive preview. This is the user's own authored content.
 */
const ZonePreview: React.FC<{ craftState: string | null; zone: 'header' | 'footer' }> = ({
  craftState,
  zone,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);

  const renderedHtml = useMemo(() => {
    if (!craftState) return null;
    try {
      const result = exportBodyHtml(craftState);
      return result.html || null;
    } catch {
      return null;
    }
  }, [craftState]);

  // Set the rendered HTML into the container via ref (user-authored content)
  useEffect(() => {
    if (containerRef.current && renderedHtml) {
      containerRef.current.textContent = '';
      const wrapper = document.createElement('div');
      wrapper.innerHTML = renderedHtml; // user's own site content
      while (wrapper.firstChild) {
        containerRef.current.appendChild(wrapper.firstChild);
      }
    }
  }, [renderedHtml]);

  if (!renderedHtml) {
    return (
      <div
        data-zone-preview={zone}
        style={{
          width: '100%',
          // Slim hint bar, not a content-height band — an empty zone should not
          // read as a stray spacer between the page and the header/footer.
          padding: '5px 12px',
          backgroundColor: zone === 'header' ? '#ffffff' : '#0f172a',
          color: zone === 'header' ? '#9ca3af' : '#64748b',
          textAlign: 'center',
          fontSize: 11,
          fontStyle: 'italic',
          borderBottom: zone === 'header' ? '1px dashed rgba(148,163,184,0.25)' : 'none',
          borderTop: zone === 'footer' ? '1px dashed rgba(148,163,184,0.25)' : 'none',
          position: 'relative',
          pointerEvents: 'none',
          userSelect: 'none',
        }}
      >
        {zone === 'header'
          ? 'Header (empty -- click Edit Header in Pages tab)'
          : 'Footer (empty -- click Edit Footer in Pages tab)'}
        <div style={{
          position: 'absolute', top: 2, right: 6,
          fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.5px',
          color: '#f59e0b', background: 'rgba(245,158,11,0.12)', padding: '1px 5px', borderRadius: 3,
        }}>
          {zone}
        </div>
      </div>
    );
  }

  return (
    <div
      ref={containerRef}
      data-zone-preview={zone}
      className="zone-preview-sep"
      style={{
        width: '100%',
        position: 'relative',
        pointerEvents: 'none',
        userSelect: 'none',
        borderBottom: zone === 'header' ? '1px dashed rgba(148,163,184,0.25)' : 'none',
        borderTop: zone === 'footer' ? '1px dashed rgba(148,163,184,0.25)' : 'none',
      }}
    />
  );
};

/**
 * First-run hint shown over the canvas drop area once the current page's
 * root node exists and has no children yet. Hidden the instant something
 * is dropped in, and while a drag is in progress (so it never fights the
 * drop-target UI). `pointer-events: none` (see .empty-canvas-hint in
 * editor.css) keeps it from intercepting clicks/drops meant for the
 * underlying empty canvas.
 */
export const EmptyCanvasHint: React.FC = () => {
  const { isEmpty, isDragging } = useEditor((state) => {
    const root = state.nodes['ROOT'];
    return {
      isEmpty: !!root && root.data.nodes.length === 0,
      isDragging: state.events.dragged.size > 0,
    };
  });
  const isMobile = useIsMobile();

  if (!isEmpty || isDragging) return null;

  return (
    <div className="empty-canvas-hint">
      <i className="fa fa-cubes" aria-hidden />
      <span>
        {isMobile
          ? <>Tap <strong>Blocks</strong> below to add content, or pick a Template to start.</>
          : 'Drag blocks from the left panel, or pick a Template to start.'}
      </span>
    </div>
  );
};

export const Canvas: React.FC<CanvasProps> = ({ device, showGuides }) => {
  const width = DEVICE_WIDTHS[device];
  const { isEditingHeader, isEditingFooter, headerPage, footerPage } = usePages();

  const isEditingRegularPage = !isEditingHeader && !isEditingFooter;

  // Fast-follow item 4: while `MobileSelectionToolbar` is up (fixed, ~53px
  // tall, just above the tab bar), it covers whatever content was at the
  // very bottom of the canvas's own scroll area -- on a short page, the
  // last section could sit permanently under the toolbar with no way to
  // scroll past it. Mirrors that toolbar's own visibility condition
  // (`selectedId && activeSheet === null`) exactly, computed independently
  // here since Canvas has no other reason to depend on the toolbar
  // component itself.
  const isMobile = useIsMobile();
  const { activeSheet } = useMobileChrome();
  const { selectedId } = useEditor((state) => {
    const selected = state.events.selected;
    const id = selected && selected.size > 0 ? (Array.from(selected)[0] as string) : null;
    return { selectedId: id && id !== 'ROOT' ? id : null };
  });
  const mobileToolbarVisible = isMobile && !!selectedId && activeSheet === null;

  // Fast-follow item 3: `MobileSelectionToolbar`'s "Style" tap scrolls the
  // selected node up towards the top of the canvas so it stays visible
  // above the Styles sheet (~65dvh tall) -- but that scroll is still bound
  // by the canvas's own natural scroll range. For a selected node near the
  // END of the content (very plausibly the last section on the page --
  // exactly the kind of node someone just added/duplicated and wants to
  // style), there may not be enough scrollable distance below it to bring
  // its top all the way up to the visible band above the sheet; the browser
  // simply clamps at its existing max scrollTop, leaving the node's top
  // stuck behind the sheet with nothing anyone can do about it (verified
  // live: the last section of a page landed under the sheet even after the
  // scroll-into-view ran). Pad the canvas with a full extra viewport's
  // worth of scroll room while the sheet is open with a selection, exactly
  // as `has-mobile-selection-toolbar` (item 4) already pads it for the
  // fixed toolbar -- generous enough that ANY node, including the very
  // last one, can always be scrolled with its top reaching the very top of
  // the canvas (comfortably within the "top ~30%" target).
  const mobileStylesSheetPad = isMobile && !!selectedId && activeSheet === 'styles';

  const frameStyle = isEditingHeader
    ? { minHeight: '60px', backgroundColor: '#ffffff', padding: '12px 24px', display: 'flex', alignItems: 'center' }
    : isEditingFooter
    ? { minHeight: '60px', backgroundColor: '#0f172a', color: '#94a3b8', padding: '40px 24px', textAlign: 'center' as const }
    : { minHeight: '100vh', backgroundColor: '#ffffff' };

  const frameTag = isEditingHeader ? 'header' : isEditingFooter ? 'footer' : 'div';

  return (
    <div
      className={`editor-canvas${mobileToolbarVisible ? ' has-mobile-selection-toolbar' : ''}${
        mobileStylesSheetPad ? ' has-mobile-styles-sheet' : ''
      }`}
    >
      <div
        className={`canvas-device-frame${showGuides ? '' : ' guides-off'}`}
        style={{
          width,
          maxWidth: '100%',
          margin: '0 auto',
          transition: 'width 0.3s ease',
          minHeight: '100%',
        }}
      >
        {(isEditingHeader || isEditingFooter) && (
          <div style={{
            background: 'rgba(245, 158, 11, 0.1)',
            borderBottom: '1px solid rgba(245, 158, 11, 0.3)',
            padding: '6px 12px',
            fontSize: 11,
            fontWeight: 600,
            color: '#f59e0b',
            display: 'flex',
            alignItems: 'center',
            gap: 6,
          }}>
            <i className={`fa ${isEditingHeader ? 'fa-window-maximize' : 'fa-window-minimize'}`} />
            Editing {isEditingHeader ? 'Header' : 'Footer'} -- This content will appear on all pages
          </div>
        )}

        {isEditingRegularPage && (
          <ZonePreview craftState={headerPage.craftState} zone="header" />
        )}

        <div style={{ position: 'relative' }}>
          <Frame>
            <Element
              is={Container}
              canvas
              tag={frameTag}
              style={frameStyle}
            />
          </Frame>
          {isEditingRegularPage && <EmptyCanvasHint />}
        </div>

        {isEditingRegularPage && (
          <ZonePreview craftState={footerPage.craftState} zone="footer" />
        )}
      </div>
    </div>
  );
};
