import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import { useEditor } from '@craftjs/core';
import { usePages } from '../../state/PageContext';
import { useSiteDesign } from '../../state/SiteDesignContext';
import {
  allTemplates,
  TemplateDefinition,
  TemplateComponent,
  TemplateCategory,
} from '../../templates';
import { clickableProps } from '../../utils/a11y';
import { Modal } from '../../ui/Modal';
import { buildNodeTree } from '../../utils/craft-tree';
import { templateComponentToTreeNode } from '../../templates/apply-template';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface TemplateModalProps {
  open: boolean;
  onClose: () => void;
}

type FilterTab = 'all' | TemplateCategory;

const TABS: { label: string; value: FilterTab }[] = [
  { label: 'All', value: 'all' },
  { label: 'Business', value: 'business' },
  { label: 'Creative', value: 'creative' },
  { label: 'Personal', value: 'personal' },
  { label: 'Community', value: 'community' },
];

const CATEGORY_COLORS: Record<TemplateCategory, string> = {
  business: '#3b82f6',
  creative: '#a855f7',
  personal: '#f59e0b',
  community: '#10b981',
};

// ---------------------------------------------------------------------------
// Modal Component
// ---------------------------------------------------------------------------

export const TemplateModal: React.FC<TemplateModalProps> = ({ open, onClose }) => {
  const { actions, query } = useEditor();
  const { pages, addPage, switchPage, deletePage, editHeader, editFooter } = usePages();
  const { updateDesign } = useSiteDesign();

  const [activeTab, setActiveTab] = useState<FilterTab>('all');
  const [confirmTemplate, setConfirmTemplate] = useState<TemplateDefinition | null>(null);
  const [applyDesign, setApplyDesign] = useState(true);
  const [loading, setLoading] = useState(false);

  // Guards state updates after the component has unmounted mid-sequence.
  const mountedRef = useRef(true);
  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);

  // Escape / backdrop-click close the confirmation dialog first if it's open,
  // otherwise close the modal. Passed to <Modal> below, which handles the
  // Escape listener and the backdrop-click detection itself; the header's own
  // close button (X) below still uses the raw `onClose` prop directly, so it
  // always fully closes the modal even mid-confirmation (unchanged behavior).
  const handleModalClose = useCallback(() => {
    if (confirmTemplate) setConfirmTemplate(null);
    else onClose();
  }, [confirmTemplate, onClose]);

  // Filter templates by category
  const filtered = useMemo(() => {
    if (activeTab === 'all') return allTemplates;
    return allTemplates.filter((t) => t.category === activeTab);
  }, [activeTab]);

  /**
   * Add all components from a template definition onto the current (empty) canvas ROOT.
   * Converts each `TemplateComponent` (the plain `{type, props, children?}`
   * shape templates author) to a `SerializedTreeNode` and runs it through
   * `buildNodeTree` (sanitize -> flatten -> materialize), the same tree pipeline
   * already used for AI-generated content. This recurses into nested
   * `children` (e.g. a header/footer `Container` wrapping `Logo`/`Menu`, or a
   * page `Section` wrapping a `Heading`) AND correctly routes them through a
   * component's SHELL_INNER linked canvas / linked columns where needed --
   * see `templates/apply-template.ts` for the two bugs this fixes (dropped
   * children, and a naive `parseReactElement` tree crashing `Section`/
   * `BackgroundSection`/`FormContainer`/`ColumnLayout`).
   */
  const addTemplateComponents = useCallback(
    (components: TemplateComponent[]) => {
      for (const comp of components) {
        try {
          const tree = buildNodeTree(query, templateComponentToTreeNode(comp));
          actions.addNodeTree(tree, 'ROOT');
        } catch (e) {
          console.warn(`Failed to build template component tree for type "${comp.type}":`, e);
        }
      }
    },
    [query, actions],
  );

  /**
   * Clear the current canvas by deleting all children of ROOT.
   */
  const clearCanvas = useCallback(() => {
    try {
      const rootNode = query.node('ROOT').get();
      const childIds = [...(rootNode.data.nodes || [])];
      childIds.forEach((id) => {
        try {
          actions.delete(id);
        } catch {
          // Node may already be removed
        }
      });
    } catch {
      // ROOT doesn't exist yet or is empty -- that's fine
    }
  }, [query, actions]);

  /** Promise-based `setTimeout` — lets the staged apply steps below be awaited
   * in sequence instead of chained via nested callbacks. */
  const wait = useCallback((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)), []);

  /**
   * Switch to a zone (header/footer), clear it, and add the template's
   * components, giving Craft.js a tick to settle between each step.
   */
  const applyZone = useCallback(
    async (switchFn: () => void, components: TemplateComponent[]) => {
      switchFn();
      await wait(30);
      try {
        clearCanvas();
        await wait(20);
        try {
          addTemplateComponents(components);
        } catch (e) {
          console.warn('Failed to add zone components:', e);
        }
      } catch (e) {
        console.warn('Failed to clear zone:', e);
      }
      await wait(30);
    },
    [wait, clearCanvas, addTemplateComponents],
  );

  /**
   * After all pages are loaded, apply header and footer template content.
   * Switches to header/footer editing mode, clears, adds components, then returns to firstPageId.
   */
  const applyHeaderFooter = useCallback(
    async (tpl: TemplateDefinition, firstPageId: string) => {
      const hasHeader = tpl.header?.components?.length > 0;
      const hasFooter = tpl.footer?.components?.length > 0;

      if (hasHeader) await applyZone(editHeader, tpl.header.components);
      if (hasFooter) await applyZone(editFooter, tpl.footer.components);

      // Switch back to the first page
      switchPage(firstPageId);
      await wait(30);
    },
    [applyZone, switchPage, editHeader, editFooter, wait],
  );

  // Load the selected template. Awaits the full staged sequence (clear, add
  // components, add pages, apply header/footer) before closing the modal, so
  // "Loading…" stays visible for the duration and onClose() never fires
  // while the sequence is still mutating a canvas the dialog just tore down.
  const handleLoad = useCallback(async () => {
    if (!confirmTemplate) return;
    setLoading(true);

    const tpl = confirmTemplate;
    setConfirmTemplate(null);

    try {
      // 1. Optionally apply design tokens
      if (applyDesign && tpl.design) {
        updateDesign(tpl.design);
      }

      // 2. Remove all pages except the first
      const currentPages = [...pages];
      const keepId = currentPages[0]?.id;
      for (let i = currentPages.length - 1; i >= 1; i--) {
        deletePage(currentPages[i].id);
      }

      // 3. Clear the current canvas and add the first template page's components
      clearCanvas();
      // Short delay to let the clear settle before adding new nodes
      await wait(20);

      const firstPage = tpl.pages[0];
      addTemplateComponents(firstPage.content.components);

      // 4. Add remaining pages (if multi-page template)
      if (tpl.pages.length > 1) {
        await wait(30);
        for (let pageIndex = 1; pageIndex < tpl.pages.length; pageIndex++) {
          const pageDef = tpl.pages[pageIndex];
          addPage(pageDef.name, pageDef.slug);

          // After addPage, the new page is active with an empty canvas.
          // Give a tick for Craft.js to settle, then add components.
          await wait(30);
          try {
            addTemplateComponents(pageDef.content.components);
          } catch (e) {
            console.warn('Failed to add components for page', pageDef.name, e);
          }
          await wait(30);
        }

        // Switch back to the first page before applying header/footer
        if (keepId) switchPage(keepId);
        await wait(30);
      }

      // 5. Apply header and footer template content
      if (keepId) {
        await applyHeaderFooter(tpl, keepId);
      }
    } catch (e) {
      console.error('Failed to load template:', e);
    } finally {
      if (mountedRef.current) setLoading(false);
      onClose();
    }
  }, [confirmTemplate, applyDesign, pages, addPage, switchPage, deletePage, updateDesign, addTemplateComponents, clearCanvas, applyHeaderFooter, wait, onClose]);

  // Mobile-A2: portaled to `document.body` -- TopBar.tsx mounts this modal
  // as a child of `.topbar`, which (as a flex item with its own z-index)
  // forms its own stacking context. That trapped the modal's fixed-position
  // backdrop underneath the mobile tab bar (z-index: var(--z-tabbar)) no
  // matter how high the modal's own z-index was set. Portaling escapes that
  // stacking context entirely so `--z-modal` (see editor.css) is evaluated
  // at the document root, same as SitesmithModal.
  return createPortal(
    <Modal open={open} onClose={handleModalClose}>
      <div style={modalStyle}>
        {/* Header */}
        <div style={modalHeaderStyle}>
          <div>
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: '#e4e4e7' }}>
              Templates
            </h2>
            <p style={{ margin: '4px 0 0', fontSize: 12, color: '#71717a' }}>
              Choose a template to get started quickly
            </p>
          </div>
          <button
            onClick={onClose}
            className="template-modal-close-btn"
            style={closeButtonStyle}
            title="Close"
            aria-label="Close"
            onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.background = 'var(--color-bg-hover)'; (e.currentTarget as HTMLElement).style.color = 'var(--color-text)'; }}
            onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.background = 'transparent'; (e.currentTarget as HTMLElement).style.color = '#71717a'; }}
          >
            <i className="fa fa-times" aria-hidden />
          </button>
        </div>

        {/* Filter Tabs -- horizontally scrollable (tabBarStyle sets
            overflowX: 'auto') so the row never wraps/overflows the modal at
            narrow widths; template-modal-tab-btn below keeps each tab from
            shrinking below a comfortable touch target on mobile. */}
        <div className="template-modal-tabbar" style={tabBarStyle}>
          {TABS.map((tab) => (
            <button
              key={tab.value}
              className="template-modal-tab-btn"
              onClick={() => setActiveTab(tab.value)}
              style={{
                ...tabStyle,
                ...(activeTab === tab.value ? tabActiveStyle : {}),
              }}
              onMouseEnter={(e) => {
                if (activeTab !== tab.value) (e.currentTarget as HTMLElement).style.background = 'var(--color-bg-hover)';
              }}
              onMouseLeave={(e) => {
                if (activeTab !== tab.value) (e.currentTarget as HTMLElement).style.background = 'transparent';
              }}
            >
              {tab.label}
            </button>
          ))}
        </div>

        {/* Template Grid */}
        <div style={gridContainerStyle}>
          <div style={gridStyle}>
            {filtered.map((tpl) => (
              <TemplateCard
                key={tpl.id}
                template={tpl}
                onSelect={() => setConfirmTemplate(tpl)}
              />
            ))}
            {filtered.length === 0 && (
              <div style={{ gridColumn: '1 / -1', textAlign: 'center', padding: 40, color: '#71717a' }}>
                No templates in this category.
              </div>
            )}
          </div>
        </div>

        {/* Confirmation Dialog */}
        {confirmTemplate && (
          <div style={confirmOverlayStyle} onClick={() => setConfirmTemplate(null)}>
            <div style={confirmDialogStyle} onClick={(e) => e.stopPropagation()}>
              <h3 style={{ margin: '0 0 8px', fontSize: 16, fontWeight: 700, color: '#e4e4e7' }}>
                Load "{confirmTemplate.name}"?
              </h3>
              <p style={{ margin: '0 0 20px', fontSize: 13, color: '#a1a1aa' }}>
                This will replace your current content with the template pages and components.
              </p>

              <label
                style={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: 10,
                  fontSize: 13,
                  color: '#e4e4e7',
                  cursor: 'pointer',
                  marginBottom: 24,
                  padding: '10px 12px',
                  backgroundColor: 'var(--color-bg-elevated)',
                  borderRadius: 6,
                  border: '1px solid var(--color-border)',
                }}
              >
                <input
                  type="checkbox"
                  checked={applyDesign}
                  onChange={(e) => setApplyDesign(e.target.checked)}
                  style={{ width: 16, height: 16, accentColor: '#3b82f6', cursor: 'pointer' }}
                />
                Apply template colors and fonts to site design
              </label>

              <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
                <button
                  onClick={() => setConfirmTemplate(null)}
                  style={{
                    padding: '8px 20px',
                    fontSize: 13,
                    fontWeight: 600,
                    color: '#a1a1aa',
                    background: 'var(--color-bg-base)',
                    border: '1px solid var(--color-border)',
                    borderRadius: 6,
                    cursor: 'pointer',
                  }}
                >
                  Cancel
                </button>
                <button
                  onClick={handleLoad}
                  disabled={loading}
                  style={{
                    padding: '8px 24px',
                    fontSize: 13,
                    fontWeight: 600,
                    color: '#ffffff',
                    background: '#3b82f6',
                    border: 'none',
                    borderRadius: 6,
                    cursor: loading ? 'wait' : 'pointer',
                    opacity: loading ? 0.7 : 1,
                  }}
                >
                  {loading ? 'Loading...' : 'Load Template'}
                </button>
              </div>
            </div>
          </div>
        )}
      </div>
    </Modal>,
    document.body,
  );
};

// ---------------------------------------------------------------------------
// TemplateCard sub-component
// ---------------------------------------------------------------------------

const TemplateCard: React.FC<{
  template: TemplateDefinition;
  onSelect: () => void;
}> = ({ template, onSelect }) => {
  const [hovered, setHovered] = useState(false);

  return (
    <div
      {...clickableProps(onSelect)}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        borderRadius: 8,
        border: `1px solid ${hovered ? 'var(--color-accent)' : 'var(--color-border)'}`,
        backgroundColor: hovered ? 'var(--color-bg-elevated)' : 'var(--color-bg-surface)',
        cursor: 'pointer',
        overflow: 'hidden',
        transition: 'all 0.2s ease',
        transform: hovered ? 'translateY(-2px)' : 'none',
        boxShadow: hovered ? '0 4px 12px rgba(0,0,0,0.3)' : 'none',
      }}
    >
      {/* Thumbnail */}
      <div
        style={{
          width: '100%',
          height: 120,
          backgroundColor: '#1a1a24',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          overflow: 'hidden',
        }}
      >
        <img
          src={template.thumbnail}
          alt={template.name}
          style={{ width: '100%', height: '100%', objectFit: 'contain' }}
        />
      </div>

      {/* Info */}
      <div style={{ padding: '12px 14px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
          <span style={{ fontSize: 13, fontWeight: 600, color: '#e4e4e7' }}>
            {template.name}
          </span>
          <span
            style={{
              fontSize: 10,
              fontWeight: 600,
              textTransform: 'uppercase',
              letterSpacing: '0.5px',
              color: CATEGORY_COLORS[template.category],
              backgroundColor: `${CATEGORY_COLORS[template.category]}18`,
              padding: '2px 6px',
              borderRadius: 4,
            }}
          >
            {template.category}
          </span>
        </div>
        <p style={{ margin: 0, fontSize: 11, color: '#71717a', lineHeight: 1.4 }}>
          {template.description}
        </p>
        <div style={{ marginTop: 8, display: 'flex', gap: 8, alignItems: 'center' }}>
          <span
            style={{
              fontSize: 10,
              color: '#52525b',
              display: 'flex',
              alignItems: 'center',
              gap: 4,
            }}
          >
            <i className="fa fa-file-o" style={{ fontSize: 9 }} />
            {template.isMultiPage ? `${template.pages.length} pages` : 'Single page'}
          </span>
        </div>
      </div>
    </div>
  );
};

// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------

const modalStyle: React.CSSProperties = {
  width: '90vw',
  maxWidth: 900,
  maxHeight: '85vh',
  backgroundColor: 'var(--color-bg-surface)',
  borderRadius: 12,
  border: '1px solid var(--color-border)',
  display: 'flex',
  flexDirection: 'column',
  overflow: 'hidden',
  boxShadow: '0 20px 60px rgba(0,0,0,0.5)',
};

const modalHeaderStyle: React.CSSProperties = {
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'space-between',
  padding: '16px 20px',
  borderBottom: '1px solid var(--color-border)',
  flexShrink: 0,
};

const closeButtonStyle: React.CSSProperties = {
  width: 32,
  height: 32,
  display: 'inline-flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 14,
  color: '#71717a',
  background: 'transparent',
  border: 'none',
  borderRadius: 6,
  cursor: 'pointer',
};

const tabBarStyle: React.CSSProperties = {
  display: 'flex',
  gap: 4,
  padding: '12px 20px',
  borderBottom: '1px solid var(--color-border)',
  flexShrink: 0,
  overflowX: 'auto',
};

const tabStyle: React.CSSProperties = {
  padding: '6px 16px',
  fontSize: 12,
  fontWeight: 500,
  color: '#71717a',
  background: 'transparent',
  border: '1px solid transparent',
  borderRadius: 6,
  cursor: 'pointer',
  whiteSpace: 'nowrap',
  transition: 'all 0.15s ease',
};

const tabActiveStyle: React.CSSProperties = {
  color: '#e4e4e7',
  background: 'var(--color-bg-elevated)',
  borderColor: 'var(--color-border)',
};

const gridContainerStyle: React.CSSProperties = {
  flex: 1,
  overflowY: 'auto',
  padding: '16px 20px 20px',
};

const gridStyle: React.CSSProperties = {
  display: 'grid',
  gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))',
  gap: 16,
};

const confirmOverlayStyle: React.CSSProperties = {
  position: 'absolute',
  top: 0,
  left: 0,
  right: 0,
  bottom: 0,
  backgroundColor: 'rgba(0, 0, 0, 0.5)',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  borderRadius: 12,
  zIndex: 1,
};

const confirmDialogStyle: React.CSSProperties = {
  width: '90%',
  maxWidth: 420,
  padding: '24px',
  backgroundColor: 'var(--color-bg-surface)',
  borderRadius: 10,
  border: '1px solid var(--color-border)',
  boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
};
