import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

/**
 * Open a noVNC iframe inside a Document Picture-in-Picture window.
 *
 * Document PiP (`window.documentPictureInPicture`) is a Chromium-only API
 * (Chrome / Edge / Arc / Opera 116+) that pops out an arbitrary HTML document
 * into an always-on-top floating window. Firefox / Safari don't support it
 * yet — `supported` will be false there and `open` becomes a no-op.
 *
 * Additional gates (any of these flips `supported` to false):
 *   - secure context required (HTTPS or localhost) — Chrome enforces this
 *   - top-level document (or the host iframe must allow
 *     `document-picture-in-picture` via Permissions Policy)
 *
 * If `open` fails at runtime (popup blocked, permissions, etc) the failure
 * surface as `lastError` so the button can display it instead of doing
 * nothing visible. The error is also console.error'd with full context.
 *
 * The view that uses this hook should:
 *   1. Render a `<PipButton>` (or equivalent) wired to `open` / `close`.
 *   2. When `isOpen` is true, hide its own `<iframe>` so the same noVNC URL
 *      isn't loaded twice. Show a small placeholder instead.
 */
export interface PipController {
  /** True if Document PiP is usable in this context. */
  supported: boolean;
  /**
   * Reason `supported` is false (e.g., 'browser', 'insecure-context',
   * 'iframe'). Undefined when supported. Useful for tooltip hints.
   */
  unsupportedReason?: 'browser' | 'insecure-context' | 'iframe' | null;
  /** True while the PiP window is open. */
  isOpen: boolean;
  /** Last open() failure reason, cleared on next successful open. */
  lastError: string | null;
  /** Open the PiP window. No-op if unsupported or already open. */
  open: () => Promise<void>;
  /** Close the PiP window. No-op if not open. */
  close: () => void;
}

interface DocumentPictureInPicture {
  requestWindow: (options?: { width?: number; height?: number }) => Promise<Window>;
}

declare global {
  interface Window {
    documentPictureInPicture?: DocumentPictureInPicture;
  }
}

function detectSupport(): { supported: boolean; reason: PipController['unsupportedReason'] } {
  if (typeof window === 'undefined') return { supported: false, reason: 'browser' };
  if (!('documentPictureInPicture' in window)) return { supported: false, reason: 'browser' };
  if (typeof window.isSecureContext === 'boolean' && !window.isSecureContext) {
    return { supported: false, reason: 'insecure-context' };
  }
  // Inside a same-origin iframe documentPictureInPicture exists but
  // requestWindow throws unless the parent grants permission via
  // Permissions Policy. We can't reliably detect that without trying, so
  // we leave the button enabled and surface lastError on failure.
  if (window.top !== window.self) {
    // Still try — many cases work fine. Just flag for diagnostics.
    return { supported: true, reason: null };
  }
  return { supported: true, reason: null };
}

export function usePictureInPicture(
  novncPath: string | null | undefined,
  title?: string,
): PipController {
  const { t } = useTranslation('console');
  const [isOpen, setIsOpen] = useState(false);
  const [lastError, setLastError] = useState<string | null>(null);
  const winRef = useRef<Window | null>(null);

  const detected = detectSupport();
  const { supported, reason } = detected;

  const close = useCallback(() => {
    const w = winRef.current;
    if (w && !w.closed) {
      w.close();
    }
    winRef.current = null;
    setIsOpen(false);
  }, []);

  const open = useCallback(async () => {
    setLastError(null);
    if (!supported) {
      const msg = reason === 'insecure-context'
        ? t('pip.insecureContext')
        : t('pip.unsupported');
      setLastError(msg);
      console.warn('[pip] open blocked:', { supported, reason });
      return;
    }
    if (!novncPath) {
      setLastError(t('pip.noNovncUrl'));
      return;
    }
    if (winRef.current && !winRef.current.closed) {
      // Already open: focus existing window
      try { winRef.current.focus(); } catch { /* ignore */ }
      return;
    }

    const pipApi = window.documentPictureInPicture;
    if (!pipApi) {
      setLastError(t('pip.apiUnavailable'));
      return;
    }

    let pipWindow: Window;
    try {
      pipWindow = await pipApi.requestWindow({ width: 800, height: 600 });
    } catch (e) {
      const errMsg = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
      console.error('[pip] requestWindow failed', e);
      let hint = errMsg;
      if (errMsg.toLowerCase().includes('user activation') || errMsg.toLowerCase().includes('user gesture')) {
        hint += t('pip.hintUserGesture');
      } else if (errMsg.toLowerCase().includes('permission')) {
        hint += t('pip.hintPermission');
      }
      setLastError(hint);
      return;
    }

    try {
      winRef.current = pipWindow;
      const doc = pipWindow.document;
      if (title) {
        const titleEl = doc.createElement('title');
        titleEl.textContent = title;
        doc.head.appendChild(titleEl);
      }

      const style = doc.createElement('style');
      style.textContent = `
        html, body { margin: 0; padding: 0; height: 100%; background: #000; overflow: hidden; }
        iframe { width: 100vw; height: 100vh; border: 0; display: block; }
      `;
      doc.head.appendChild(style);

      const iframe = doc.createElement('iframe');
      iframe.src = novncPath;
      iframe.allow = 'clipboard-read; clipboard-write';
      iframe.title = title ?? 'noVNC';
      doc.body.appendChild(iframe);

      const onClose = () => {
        winRef.current = null;
        setIsOpen(false);
      };
      pipWindow.addEventListener('pagehide', onClose);
      pipWindow.addEventListener('unload', onClose);

      setIsOpen(true);
    } catch (e) {
      const errMsg = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
      console.error('[pip] mounting iframe in PiP window failed', e);
      setLastError(t('pip.initFailed', { msg: errMsg }));
      try { pipWindow.close(); } catch { /* ignore */ }
      winRef.current = null;
    }
  }, [supported, reason, novncPath, title, t]);

  // Close the PiP window if the parent component unmounts so we don't leak
  // floating windows after navigation.
  useEffect(() => {
    return () => {
      const w = winRef.current;
      if (w && !w.closed) w.close();
      winRef.current = null;
    };
  }, []);

  // If novncPath becomes unavailable while PiP is open (session destroyed,
  // task ended), close the PiP — the iframe inside would just show 404 and
  // confuse the user.
  useEffect(() => {
    if (isOpen && !novncPath) {
      close();
    }
  }, [isOpen, novncPath, close]);

  return {
    supported,
    unsupportedReason: reason,
    isOpen,
    lastError,
    open,
    close,
  };
}
