import React, { useEffect, useMemo, useRef } from 'react';
// import '@excalidraw/excalidraw/dist/excalidraw.min.css';
import { Excalidraw, exportToBlob, exportToSvg } from '@excalidraw/excalidraw';
import type { AppState, ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types/types';
import type { ExcalidrawWrapperProps, Scene, SceneChangeDetail, ReadyDetail } from './types';

/**
 * React wrapper mounted inside the <excalidraw-editor> custom element.
 * It relies on r2wc to pass the host element via a non-attribute property `__host`.
 */
export default function ExcalidrawWrapper(props: ExcalidrawWrapperProps & { __host?: HTMLElement; hostRef?: HTMLElement }) {
  const apiRef = useRef<ExcalidrawImperativeAPI | null>(null);
  const hostRef = useRef<HTMLElement | null>(null);
  const pendingReadyRef = useRef<ExcalidrawImperativeAPI | null>(null);
  const pendingSceneEventsRef = useRef<SceneChangeDetail[]>([]);
  const lastDetailRef = useRef<SceneChangeDetail | null>(null);

  const resolveHost = (candidate?: HTMLElement | null) => {
    if (candidate && hostRef.current !== candidate) {
      hostRef.current = candidate;
      console.log('[excalidraw-editor] host resolved', { hasHost: true });
    }
  };

  resolveHost((props as any).hostRef as HTMLElement | undefined);
  resolveHost((props as any).__host as HTMLElement | undefined);

  // Sync dark/light mode with export utils defaults
  const theme = props.theme === 'dark' ? 'dark' : 'light';
  const lang = props.lang || 'fr';

  const onChange = (elements: any[], appState: Partial<AppState>, files: any) => {
    // CRITICAL DEBUG: Log raw parameters
    console.log('[excalidraw-editor] 🔍 onChange called', {
      elementsLength: elements?.length,
      elementsIsArray: Array.isArray(elements),
      elementsRaw: elements,
      appStateKeys: appState ? Object.keys(appState) : [],
      filesKeys: files ? Object.keys(files) : []
    });
    
    const detail: SceneChangeDetail = { elements, appState, files, source: 'user' };
    lastDetailRef.current = detail;
    console.log('[excalidraw-editor] 📝 SCENE-CHANGE will dispatch', { 
      elCount: Array.isArray(elements) ? elements.length : 'n/a',
      elementsType: typeof elements,
      isArray: Array.isArray(elements),
      viewMode: appState?.viewModeEnabled,
      propsReadOnly: props.readOnly,
      firstElement: elements?.[0] ? { id: elements[0].id, type: elements[0].type } : null
    });
    
    const host = hostRef.current;
    if (!host) {
      console.warn('[excalidraw-editor] host unavailable during scene-change, queueing event');
      pendingSceneEventsRef.current.push(detail);
      return;
    }
    
    // Always dispatch - Angular will handle filtering via hash comparison
    host.dispatchEvent(new CustomEvent('scene-change', { detail, bubbles: true, composed: true }));
    console.log('[excalidraw-editor] ✅ SCENE-CHANGE dispatched to host');
  };

  // When API becomes available
  const onApiReady = (api: ExcalidrawImperativeAPI) => {
    console.log('[excalidraw-editor] onApiReady', !!api);
    apiRef.current = api;
    const host = hostRef.current;
    if (host) {
      (host as any).__excalidrawAPI = api;
      host.dispatchEvent(new CustomEvent<ReadyDetail>('ready', { detail: { apiAvailable: true }, bubbles: true, composed: true }));
      // Force a couple of refresh cycles to layout the canvas once API is ready
      try { api.refresh?.(); } catch {}
      queueMicrotask(() => { try { api.refresh?.(); } catch {} });
      setTimeout(() => { try { api.refresh?.(); } catch {} }, 0);
    } else {
      pendingReadyRef.current = api;
    }
  };

  // Expose imperative export helpers via the host methods (define.ts wires prototypes)
  useEffect(() => {
    resolveHost((props as any).hostRef as HTMLElement | undefined);
    resolveHost((props as any).__host as HTMLElement | undefined);

    const host = hostRef.current;
    if (!host) return;

    if (pendingReadyRef.current) {
      (host as any).__excalidrawAPI = pendingReadyRef.current;
      host.dispatchEvent(new CustomEvent<ReadyDetail>('ready', { detail: { apiAvailable: true }, bubbles: true, composed: true }));
      console.log('[excalidraw-editor] flushed pending ready event');
      pendingReadyRef.current = null;
    }

    if (pendingSceneEventsRef.current.length > 0) {
      const queued = pendingSceneEventsRef.current.splice(0);
      console.log('[excalidraw-editor] flushing queued scene events', { count: queued.length });
      queued.forEach((detail) => {
        host.dispatchEvent(new CustomEvent('scene-change', { detail, bubbles: true, composed: true }));
      });
    }

    (host as any).__getScene = () => {
      const api = apiRef.current;
      if (!api) return { elements: [], appState: {}, files: {} } as Scene;
      return {
        elements: api.getSceneElements?.() ?? [],
        appState: api.getAppState?.() ?? {},
        files: api.getFiles?.() ?? {},
      } as Scene;
    };

    (host as any).__getLastEventScene = () => {
      const ld = lastDetailRef.current;
      if (!ld) return undefined;
      return { elements: ld.elements ?? [], appState: ld.appState ?? {}, files: ld.files ?? {} } as Scene;
    };

    (host as any).__emitSceneChange = () => {
      const api = apiRef.current;
      if (!api) return;
      const elements = api.getSceneElements?.() ?? [];
      const appState = api.getAppState?.() ?? {} as Partial<AppState>;
      const files = api.getFiles?.() ?? {};
      const detail = { elements, appState, files, source: 'flush' } as any;
      try {
        host.dispatchEvent(new CustomEvent('scene-change', { detail, bubbles: true, composed: true }));
      } catch {}
    };

    (host as any).__exportPNG = async (opts: { withBackground?: boolean } = {}) => {
      const api = apiRef.current;
      if (!api) return undefined;
      const elements = api.getSceneElements?.() ?? [];
      const appState = { ...(api.getAppState?.() ?? {}), exportBackground: !!opts.withBackground } as any;
      const files = api.getFiles?.() ?? {};
      return await exportToBlob({ elements, appState, files, mimeType: 'image/png', quality: 1 });
    };

    (host as any).__exportSVG = async (opts: { withBackground?: boolean } = {}) => {
      const api = apiRef.current;
      if (!api) return undefined;
      const elements = api.getSceneElements?.() ?? [];
      const appState = { ...(api.getAppState?.() ?? {}), exportBackground: !!opts.withBackground } as any;
      const files = api.getFiles?.() ?? {};
      const svgEl = await exportToSvg({ elements, appState, files });
      const svgText = new XMLSerializer().serializeToString(svgEl);
      return new Blob([svgText], { type: 'image/svg+xml' });
    };
  });

  // Ensure canvas refreshes when the host size becomes available or changes
  useEffect(() => {
    const host = hostRef.current;
    if (!host) return;
    // Force an initial refresh shortly after mount to layout the canvas
    const t = setTimeout(() => {
      try { apiRef.current?.refresh?.(); } catch {}
    }, 0);

    let ro: ResizeObserver | null = null;
    try {
      ro = new ResizeObserver(() => {
        try { apiRef.current?.refresh?.(); } catch {}
      });
      ro.observe(host);
    } catch {}

    return () => {
      clearTimeout(t);
      try { ro?.disconnect(); } catch {}
    };
  });

  // Map React props to Excalidraw props
  // IMPORTANT: Freeze initialData on first mount to avoid resetting the scene
  const initialDataRef = useRef<any>(props.initialData as any);

  return (
    <div style={{ height: '100%', width: '100%' }}>
      <Excalidraw
        excalidrawAPI={onApiReady}
        initialData={initialDataRef.current}
        viewModeEnabled={!!props.readOnly}
        theme={theme}
        langCode={lang}
        gridModeEnabled={!!props.gridMode}
        zenModeEnabled={!!props.zenMode}
        onChange={onChange}
      />
    </div>
  );
}
