/**
 * RemoteViewer Component
 *
 * Canvas-based remote desktop viewer that connects to a GuruConnect
 * agent via the relay server. Handles frame rendering and input capture.
 */

import React, { useRef, useEffect, useCallback, useState } from 'react';
import { useRemoteSession, createMouseEvent, createKeyEvent } from '../hooks/useRemoteSession';
import type { VideoFrame, ConnectionStatus, MouseEventType } from '../types/protocol';

interface RemoteViewerProps {
  serverUrl: string;
  sessionId: string;
  className?: string;
  onStatusChange?: (status: ConnectionStatus) => void;
  autoConnect?: boolean;
  showStatusBar?: boolean;
}

export const RemoteViewer: React.FC<RemoteViewerProps> = ({
  serverUrl,
  sessionId,
  className = '',
  onStatusChange,
  autoConnect = true,
  showStatusBar = true,
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const ctxRef = useRef<CanvasRenderingContext2D | null>(null);

  // Display dimensions from received frames
  const [displaySize, setDisplaySize] = useState({ width: 1920, height: 1080 });

  // Frame buffer for rendering
  const frameBufferRef = useRef<ImageData | null>(null);

  // Handle incoming video frames
  const handleFrame = useCallback((frame: VideoFrame) => {
    if (!frame.raw || !canvasRef.current) return;

    const { width, height, data, compressed, isKeyframe } = frame.raw;

    // Update display size if changed
    if (width !== displaySize.width || height !== displaySize.height) {
      setDisplaySize({ width, height });
    }

    // Get or create context
    if (!ctxRef.current) {
      ctxRef.current = canvasRef.current.getContext('2d', {
        alpha: false,
        desynchronized: true,
      });
    }

    const ctx = ctxRef.current;
    if (!ctx) return;

    // For MVP, we assume raw BGRA frames
    // In production, handle compressed frames with fzstd
    let frameData = data;

    // Create or reuse ImageData
    if (!frameBufferRef.current ||
        frameBufferRef.current.width !== width ||
        frameBufferRef.current.height !== height) {
      frameBufferRef.current = ctx.createImageData(width, height);
    }

    const imageData = frameBufferRef.current;

    // Convert BGRA to RGBA for canvas
    const pixels = imageData.data;
    const len = Math.min(frameData.length, pixels.length);

    for (let i = 0; i < len; i += 4) {
      pixels[i] = frameData[i + 2];     // R <- B
      pixels[i + 1] = frameData[i + 1]; // G <- G
      pixels[i + 2] = frameData[i];     // B <- R
      pixels[i + 3] = 255;              // A (opaque)
    }

    // Draw to canvas
    ctx.putImageData(imageData, 0, 0);
  }, [displaySize]);

  // Set up session
  const { status, connect, disconnect, sendMouseEvent, sendKeyEvent } = useRemoteSession({
    serverUrl,
    sessionId,
    onFrame: handleFrame,
    onStatusChange,
  });

  // Auto-connect on mount
  useEffect(() => {
    if (autoConnect) {
      connect();
    }
    return () => {
      disconnect();
    };
  }, [autoConnect, connect, disconnect]);

  // Update canvas size when display size changes
  useEffect(() => {
    if (canvasRef.current) {
      canvasRef.current.width = displaySize.width;
      canvasRef.current.height = displaySize.height;
      // Reset context reference
      ctxRef.current = null;
      frameBufferRef.current = null;
    }
  }, [displaySize]);

  // Get canvas rect for coordinate translation
  const getCanvasRect = useCallback(() => {
    return canvasRef.current?.getBoundingClientRect() ?? new DOMRect();
  }, []);

  // Mouse event handlers
  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    const event = createMouseEvent(e, getCanvasRect(), displaySize.width, displaySize.height, 0);
    sendMouseEvent(event);
  }, [getCanvasRect, displaySize, sendMouseEvent]);

  const handleMouseDown = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    e.preventDefault();
    const event = createMouseEvent(e, getCanvasRect(), displaySize.width, displaySize.height, 1);
    sendMouseEvent(event);
  }, [getCanvasRect, displaySize, sendMouseEvent]);

  const handleMouseUp = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    const event = createMouseEvent(e, getCanvasRect(), displaySize.width, displaySize.height, 2);
    sendMouseEvent(event);
  }, [getCanvasRect, displaySize, sendMouseEvent]);

  const handleWheel = useCallback((e: React.WheelEvent<HTMLCanvasElement>) => {
    e.preventDefault();
    const baseEvent = createMouseEvent(e, getCanvasRect(), displaySize.width, displaySize.height, 3);
    sendMouseEvent({
      ...baseEvent,
      wheelDeltaX: Math.round(e.deltaX),
      wheelDeltaY: Math.round(e.deltaY),
    });
  }, [getCanvasRect, displaySize, sendMouseEvent]);

  const handleContextMenu = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    e.preventDefault(); // Prevent browser context menu
  }, []);

  // Keyboard event handlers
  const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLCanvasElement>) => {
    e.preventDefault();
    const event = createKeyEvent(e, true);
    sendKeyEvent(event);
  }, [sendKeyEvent]);

  const handleKeyUp = useCallback((e: React.KeyboardEvent<HTMLCanvasElement>) => {
    e.preventDefault();
    const event = createKeyEvent(e, false);
    sendKeyEvent(event);
  }, [sendKeyEvent]);

  return (
    <div ref={containerRef} className={`remote-viewer ${className}`}>
      <canvas
        ref={canvasRef}
        tabIndex={0}
        onMouseMove={handleMouseMove}
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onWheel={handleWheel}
        onContextMenu={handleContextMenu}
        onKeyDown={handleKeyDown}
        onKeyUp={handleKeyUp}
        style={{
          width: '100%',
          height: 'auto',
          aspectRatio: `${displaySize.width} / ${displaySize.height}`,
          cursor: 'none', // Hide cursor, remote cursor is shown in frame
          outline: 'none',
          backgroundColor: '#1a1a1a',
        }}
      />

      {showStatusBar && (
        <div className="remote-viewer-status" style={{
          display: 'flex',
          justifyContent: 'space-between',
          padding: '4px 8px',
          backgroundColor: '#333',
          color: '#fff',
          fontSize: '12px',
          fontFamily: 'monospace',
        }}>
          <span>
            {status.connected ? (
              <span style={{ color: '#4ade80' }}>Connected</span>
            ) : (
              <span style={{ color: '#f87171' }}>Disconnected</span>
            )}
          </span>
          <span>{displaySize.width}x{displaySize.height}</span>
          {status.fps !== undefined && <span>{status.fps} FPS</span>}
          {status.latencyMs !== undefined && <span>{status.latencyMs}ms</span>}
        </div>
      )}
    </div>
  );
};

export default RemoteViewer;
