import type { CSSProperties } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useClient } from 'hooks/useClient';
import { useMounted } from 'hooks/useMounted';

export type DesktopViewProps = {
  className?: string;
  style?: CSSProperties;
};

const NOVNC_URL = '/novnc/rfb.js';

const buildWsUrl = () => {
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  const token = localStorage.getItem('BEARER_TOKEN') ?? '';
  return `${protocol}//${window.location.host}/api/desktop/ws?token=${encodeURIComponent(token)}`;
};

type RFBInstance = {
  resizeSession: boolean;
  scaleViewport: boolean;
  focusOnClick: boolean;
  disconnect: () => void;
  sendCredentials: (creds: { password: string }) => void;
  addEventListener: (type: string, listener: (ev: CustomEvent) => void) => void;
};

let rfbModulePromise: Promise<{
  default: new (target: HTMLElement, url: string, options?: { credentials?: { password?: string } }) => RFBInstance;
}> | null = null;

const loadRFB = () => {
  if (!rfbModulePromise) {
    rfbModulePromise = import(/* @vite-ignore */ NOVNC_URL) as NonNullable<typeof rfbModulePromise>;
  }
  return rfbModulePromise!;
};

export const DesktopView = ({ className, style }: DesktopViewProps) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const rfbRef = useRef<RFBInstance | null>(null);
  const isMounted = useMounted();
  const client = useClient();
  const [status, setStatus] = useState<'connecting' | 'connected' | 'disconnected' | 'error'>('connecting');
  const [errorMsg, setErrorMsg] = useState('');

  useEffect(() => {
    if (!isMounted) return;
    const container = containerRef.current;
    if (!container) return;

    let disposed = false;

    const connect = async () => {
      let password = '';
      try {
        const res = await client.get<{ password: string }>('/desktop/vnc-password');
        password = res.password;
      } catch {
        if (disposed) return;
        setStatus('error');
        setErrorMsg('Failed to fetch VNC password');
        return;
      }

      if (disposed) return;

      let RFB: Awaited<ReturnType<typeof loadRFB>>['default'];
      try {
        const mod = await loadRFB();
        RFB = mod.default;
      } catch (err) {
        console.error('[desktop] Failed to load noVNC:', err);
        if (disposed) return;
        setStatus('error');
        setErrorMsg('Failed to load noVNC library');
        return;
      }

      if (disposed) return;

      const wsUrl = buildWsUrl();
      const rfb = new RFB(container, wsUrl, {
        credentials: { password },
      });

      rfb.resizeSession = true;
      rfb.scaleViewport = true;
      rfb.focusOnClick = true;
      rfbRef.current = rfb;

      rfb.addEventListener('connect', () => {
        if (!disposed) setStatus('connected');
      });

      rfb.addEventListener('disconnect', (ev: CustomEvent) => {
        if (disposed) return;
        setStatus('disconnected');
        if (!ev.detail.clean) {
          setErrorMsg('Connection lost');
        }
      });

      rfb.addEventListener('credentialsrequired', () => {
        rfb.sendCredentials({ password });
      });

      rfb.addEventListener('securityfailure', (ev: CustomEvent) => {
        if (!disposed) {
          setStatus('error');
          setErrorMsg(ev.detail.reason || 'Security failure');
        }
      });
    };

    void connect();

    return () => {
      disposed = true;
      if (rfbRef.current) {
        try {
          rfbRef.current.disconnect();
        } catch {
          /* ignore */
        }
        rfbRef.current = null;
      }
    };
  }, [isMounted, client]);

  return (
    <div
      className={className}
      style={{ backgroundColor: '#1a1a2e', overflow: 'hidden', position: 'relative', ...style }}
    >
      {status === 'connecting' && (
        <div className="absolute inset-0 flex items-center justify-center text-sm text-muted-foreground">
          Connecting to desktop...
        </div>
      )}
      {(status === 'disconnected' || status === 'error') && (
        <div className="absolute inset-0 flex items-center justify-center text-sm text-muted-foreground">
          {errorMsg || 'Disconnected from desktop'}
        </div>
      )}
      <div ref={containerRef} style={{ width: '100%', height: '100%' }} />
    </div>
  );
};
