import { useEffect, useMemo, useRef } from 'react';
import PropTypes from 'prop-types';
import { letramentoEventBus, LETRAMENTO_EVENTS } from '../../utils/letramentoEvents';

// Allowed event types from the iframe activity.
// The HTML activity sends: window.parent.postMessage({ type: 'started' | 'running' | 'success' | 'failure' | 'completed', ...payload }, '*')
const ALLOWED_TYPES = new Set(Object.values(LETRAMENTO_EVENTS));

function generateChannelToken() {
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
    return crypto.randomUUID();
  }

  return `ltr-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
}

function resolveHtmlFile(htmlFile) {
  if (/^https?:\/\//.test(htmlFile) || /^file:\/\//.test(htmlFile)) {
    return htmlFile;
  }

  if (window.location.protocol === 'file:') {
    const relativePath = htmlFile.startsWith('/') ? htmlFile.slice(1) : htmlFile;
    return new URL(relativePath, window.location.href).toString();
  }

  return htmlFile.startsWith('/') ? htmlFile : `/${htmlFile}`;
}

function buildIframeSrc(htmlFile, channelToken) {
  const [base, existingHash = ''] = htmlFile.split('#');
  const resolvedBase = resolveHtmlFile(base);
  const hashParams = new URLSearchParams(existingHash);
  hashParams.set('channelToken', channelToken);
  return `${resolvedBase}#${hashParams.toString()}`;
}

export default function AtividadeRuntimeFrame({ htmlFile, atividadeId, reloadToken = 0, className = '' }) {
  const iframeRef = useRef(null);
  const channelToken = useMemo(
    () => generateChannelToken(),
    [atividadeId, htmlFile, reloadToken],
  );
  const iframeSrc = useMemo(
    () => buildIframeSrc(htmlFile, channelToken),
    [htmlFile, channelToken],
  );

  const focusRuntime = () => {
    const iframe = iframeRef.current;
    if (!iframe) return;

    iframe.focus();
    iframe.contentWindow?.focus();
  };

  useEffect(() => {
    const handleMessage = (event) => {
      const iframeWindow = iframeRef.current?.contentWindow;
      if (!iframeWindow || event.source !== iframeWindow) return;

      // Accept only messages from the same origin or from sandboxed iframes.
      // Sandboxed iframes (sandbox="allow-scripts" without allow-same-origin) always
      // report event.origin as the string "null" — we allow that explicitly.
      const allowedOrigin =
        event.origin === window.location.origin || event.origin === 'null';
      if (!allowedOrigin) return;

      const { type, token, ...payload } = event.data ?? {};
      if (token !== channelToken) return;
      if (!type || !ALLOWED_TYPES.has(type)) return;

      letramentoEventBus.dispatch(type, { atividadeId, ...payload });
    };

    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, [atividadeId, channelToken]);

  useEffect(() => {
    // Focus right after mount/switch so keyboard-only users can start immediately.
    const raf = window.requestAnimationFrame(() => {
      focusRuntime();
      window.setTimeout(focusRuntime, 50);
    });

    return () => window.cancelAnimationFrame(raf);
  }, [atividadeId, htmlFile, reloadToken]);

  return (
    <iframe
      key={`${atividadeId}:${reloadToken}`}
      ref={iframeRef}
      src={iframeSrc}
      title="Atividade de Letramento Digital"
      className={`w-full h-full border-0 ${className}`}
      tabIndex={-1}
      onLoad={focusRuntime}
      // allow-same-origin enables file:// subresource loading in Electron builds.
      sandbox="allow-scripts allow-same-origin"
      referrerPolicy="no-referrer"
    />
  );
}

AtividadeRuntimeFrame.propTypes = {
  htmlFile:    PropTypes.string.isRequired,
  atividadeId: PropTypes.string.isRequired,
  reloadToken: PropTypes.number,
  className:   PropTypes.string,
};
