/**
 * VncTile — Live-Desktop der QEMU-VM (noVNC in einer WebView, RFB durch RVS).
 *
 * Nur aktiv, wenn das Desktop-Panel offen ist (focused): dann WebView mounten,
 * bei 'ready' den RVS-VNC-Tunnel oeffnen. Eine kleine Steuerungs-Leiste macht
 * die VM auf dem Handy bedienbar: Tastatur einblenden (tippt in die VM),
 * Strg-Alt-Entf, und Fit ↔ 1:1 umschalten.
 */

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { NativeSyntheticEvent, StyleSheet, Text, TextInput, TextInputChangeEventData, TextInputKeyPressEventData, TouchableOpacity, View } from 'react-native';
import { WebView, WebViewMessageEvent } from 'react-native-webview';
import desktop from '../../services/desktop';
import { NOVNC_HTML } from '../assets/novncHtml';

interface Props {
  projectId: string;
  focused: boolean;
  port?: number; // VNC-Port der zu verbindenden VM (Default 5901 = Display :1)
}

// X11-Keysyms fuer Sondertasten, die kein druckbares Zeichen liefern.
const KEYSYM = { Backspace: 0xff08, Enter: 0xff0d, Tab: 0xff09 };

const VncTile: React.FC<Props> = ({ projectId, focused, port = 5901 }) => {
  const webRef = useRef<WebView>(null);
  const kbdRef = useRef<TextInput>(null);
  const bufRef = useRef('');                        // Spiegel des TextInput-Textes
  const [status, setStatus] = useState<'idle' | 'connecting' | 'connected' | 'disconnected'>('idle');
  const [kbdOn, setKbdOn] = useState(false);
  const unsubDataRef = useRef<null | (() => void)>(null);

  const teardown = useCallback(() => {
    if (unsubDataRef.current) { unsubDataRef.current(); unsubDataRef.current = null; }
    desktop.closeVnc();
  }, []);

  useEffect(() => {
    if (!focused) { teardown(); setStatus('idle'); }
    return () => teardown();
  }, [focused, teardown]);

  const ctl = useCallback((fn: string) => {
    webRef.current?.injectJavaScript(`window.ariaVncCtl && window.ariaVncCtl.${fn}(); true;`);
  }, []);

  const sendChar = useCallback((cp: number) => {
    webRef.current?.injectJavaScript(`window.ariaVncKey && window.ariaVncKey.char(${cp}); true;`);
  }, []);
  const sendKeysym = useCallback((ks: number) => {
    webRef.current?.injectJavaScript(`window.ariaVncKey && window.ariaVncKey.keysym(${ks}); true;`);
  }, []);

  // Tastatur ein-/ausblenden: echtes RN-<TextInput> fokussieren → Android oeffnet
  // die Software-Tastatur zuverlaessig (anders als ein verstecktes WebView-Feld).
  const toggleKbd = useCallback(() => {
    if (kbdOn) { kbdRef.current?.blur(); setKbdOn(false); }
    else { setKbdOn(true); setTimeout(() => kbdRef.current?.focus(), 0); }
  }, [kbdOn]);

  // Druckbare Zeichen: Prefix-Diff des (wachsenden) Feldes → nur neu Getipptes an
  // die VM. Loeschungen kommen ueber onKeyPress(Backspace), daher hier nur Inserts.
  const onKbdChange = useCallback((e: NativeSyntheticEvent<TextInputChangeEventData>) => {
    const text = e.nativeEvent.text || '';
    const prev = bufRef.current;
    let i = 0;
    const min = Math.min(prev.length, text.length);
    while (i < min && prev.charCodeAt(i) === text.charCodeAt(i)) i++;
    for (const ch of text.slice(i)) { const cp = ch.codePointAt(0); if (cp) sendChar(cp); }
    bufRef.current = text;
    if (text.length > 200) { bufRef.current = ''; kbdRef.current?.setNativeProps({ text: '' }); }
  }, [sendChar]);

  // Sondertasten: Backspace/Enter feuern auf Android zuverlaessig als keyPress.
  const onKbdKeyPress = useCallback((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
    const k = e.nativeEvent.key;
    if (k === 'Backspace') sendKeysym(KEYSYM.Backspace);
    else if (k === 'Enter') sendKeysym(KEYSYM.Enter);
  }, [sendKeysym]);

  const onMessage = useCallback((e: WebViewMessageEvent) => {
    let m: any;
    try { m = JSON.parse(e.nativeEvent.data); } catch { return; }
    if (m.event === 'ready') {
      setStatus('connecting');
      unsubDataRef.current = desktop.onVncData((b64) => {
        const js = `window.ariaVnc && window.ariaVnc.onData(${JSON.stringify(b64)}); true;`;
        webRef.current?.injectJavaScript(js);
      });
      desktop.openVnc(projectId, port);
    } else if (m.event === 'vnc_send') {
      desktop.sendInput(m.b64);
    } else if (m.event === 'vnc_close') {
      desktop.closeVnc();
    } else if (m.event === 'vnc_state') {
      if (m.state === 'connected') setStatus('connected');
      else if (m.state === 'disconnected') setStatus('disconnected');
    }
  }, [projectId, port]);

  if (!focused) {
    return (
      <View style={styles.placeholder}>
        <Text style={styles.icon}>🖥️</Text>
        <Text style={styles.text}>Desktop</Text>
        <Text style={styles.sub}>Panel öffnen zum Verbinden</Text>
      </View>
    );
  }

  const connected = status === 'connected';
  return (
    <View style={styles.container}>
      <WebView
        ref={webRef}
        style={styles.web}
        originWhitelist={['*']}
        source={{ html: NOVNC_HTML, baseUrl: 'https://aria-vnc.local/' }}
        onMessage={onMessage}
        javaScriptEnabled
        domStorageEnabled
        mixedContentMode="always"
        androidLayerType="hardware"
        keyboardDisplayRequiresUserAction={false}
      />

      {/* Verstecktes Eingabefeld: fokussiert → Android-Tastatur tippt in die VM.
          keyboardType=visible-password schaltet Autokorrektur/Vorschlaege ab und
          liefert saubere Einzelzeichen. Offscreen, aber fokussierbar. */}
      <TextInput
        ref={kbdRef}
        style={styles.hiddenInput}
        onChange={onKbdChange}
        onKeyPress={onKbdKeyPress}
        onBlur={() => setKbdOn(false)}
        keyboardType="visible-password"
        autoCapitalize="none"
        autoCorrect={false}
        spellCheck={false}
        blurOnSubmit={false}
        caretHidden
        contextMenuHidden
        multiline={false}
      />

      {/* Steuerungs-Leiste — nur wenn verbunden */}
      {connected && (
        <View style={styles.ctlBar}>
          <TouchableOpacity style={[styles.ctlBtn, kbdOn && styles.ctlBtnOn]} onPress={toggleKbd} activeOpacity={0.7}>
            <Text style={styles.ctlText}>⌨</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.ctlBtn} onPress={() => ctl('cad')} activeOpacity={0.7}>
            <Text style={styles.ctlTextSmall}>Strg+Alt+Entf</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.ctlBtn} onPress={() => ctl('toggleFit')} activeOpacity={0.7}>
            <Text style={styles.ctlText}>⤢</Text>
          </TouchableOpacity>
        </View>
      )}

      {!connected && (
        <View style={styles.overlay} pointerEvents="none">
          <Text style={styles.overlayText}>
            {status === 'connecting' ? 'Verbinde …' : status === 'disconnected' ? 'Getrennt' : ''}
          </Text>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#000000' },
  web: { flex: 1, backgroundColor: '#000000' },
  placeholder: { flex: 1, backgroundColor: '#000000', alignItems: 'center', justifyContent: 'center' },
  icon: { fontSize: 64, marginBottom: 16 },
  text: { color: '#FFFFFF', fontSize: 18, fontWeight: '700' },
  sub: { color: '#9090B0', fontSize: 14, marginTop: 8 },
  ctlBar: {
    position: 'absolute',
    top: 34,
    right: 8,
    flexDirection: 'row',
    gap: 6,
  },
  ctlBtn: {
    backgroundColor: 'rgba(18,18,42,0.9)',
    borderColor: '#2A2A3E',
    borderWidth: 1,
    borderRadius: 10,
    paddingHorizontal: 10,
    paddingVertical: 7,
    minWidth: 38,
    alignItems: 'center',
    justifyContent: 'center',
  },
  ctlBtnOn: { backgroundColor: 'rgba(0,150,255,0.85)', borderColor: '#0096FF' },
  ctlText: { color: '#E0E0F0', fontSize: 16, fontWeight: '700' },
  ctlTextSmall: { color: '#E0E0F0', fontSize: 11, fontWeight: '700' },
  // Fokussierbar (nicht display:none), aber aus dem Sichtfeld geschoben.
  hiddenInput: { position: 'absolute', width: 1, height: 1, top: -100, left: -100, opacity: 0, padding: 0 },
  overlay: { position: 'absolute', top: 12, left: 0, right: 0, alignItems: 'center' },
  overlayText: { color: '#9090B0', fontSize: 12, backgroundColor: 'rgba(0,0,0,0.6)', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 10, overflow: 'hidden' },
});

export default VncTile;
