/**
 * CodeEditorTile — Live-Code-Editor (WebView, editorHtml.ts).
 *
 * Zeigt die Dateien eines Code-Projekts aus /shared/projects/<id>/:
 *  - beim Oeffnen werden die BEREITS vorhandenen Dateien vom Brain geladen
 *    (listProjectFiles/readProjectFile) — sonst waere der Editor leer, obwohl
 *    ARIA schon Dateien geschrieben hat.
 *  - live schreibt ARIA weiter → code_file-Stream aktualisiert die offene Datei.
 * Stefan kann selbst editieren → code_file_edit zurueck an die Bridge.
 */

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { WebView, WebViewMessageEvent } from 'react-native-webview';
import codeFile from '../../services/codeFile';
import brainApi from '../../services/brainApi';
import { EDITOR_HTML } from '../assets/editorHtml';

interface Props {
  projectId: string;
}

function guessLang(path: string): string {
  const ext = (path.split('.').pop() || '').toLowerCase();
  const map: Record<string, string> = {
    js: 'javascript', ts: 'typescript', tsx: 'typescript', py: 'python',
    c: 'c', h: 'c', cpp: 'cpp', asm: 'asm', s: 'asm', sh: 'shell', bash: 'shell',
    html: 'html', css: 'css', json: 'json', yaml: 'yaml', yml: 'yaml', md: 'markdown',
    go: 'go', rs: 'rust', java: 'java', kt: 'kotlin', txt: 'text',
  };
  return map[ext] || 'text';
}

const CodeEditorTile: React.FC<Props> = ({ projectId }) => {
  const webRef = useRef<WebView>(null);
  // Pfade aus dem Brain (vorhandene Dateien) — mit Live-Dateien gemergt.
  const [serverPaths, setServerPaths] = useState<string[]>([]);
  const [currentPath, setCurrentPath] = useState<string | null>(null);
  const [loadErr, setLoadErr] = useState<string>('');

  const readyRef = useRef(false);
  const currentPathRef = useRef<string | null>(currentPath);
  currentPathRef.current = currentPath;

  // Vereinigte, sortierte Dateiliste (Live-Spiegel + Server-Dateien).
  const files = useMemo(() => {
    const set = new Set<string>(serverPaths);
    for (const f of codeFile.getFiles(projectId)) set.add(f.path);
    return Array.from(set).sort((a, b) => a.localeCompare(b));
  }, [serverPaths, projectId]);

  const sendToWeb = useCallback((payload: Record<string, unknown>) => {
    const js = `window.ariaBridge && window.ariaBridge.onMessage(${JSON.stringify(JSON.stringify(payload))}); true;`;
    webRef.current?.injectJavaScript(js);
  }, []);

  const loadFileIntoEditor = useCallback(async (path: string | null) => {
    if (!path) { sendToWeb({ cmd: 'setContent', content: '', language: 'text', version: 0 }); return; }
    // Live-Version bevorzugen (falls ARIA gerade schreibt), sonst vom Brain holen.
    const live = codeFile.getFile(projectId, path);
    if (live) {
      sendToWeb({ cmd: 'setContent', content: live.content, language: live.language, version: live.version });
      return;
    }
    try {
      const res = await brainApi.readProjectFile(projectId, path);
      sendToWeb({ cmd: 'setContent', content: res.content ?? '', language: guessLang(path), version: 0 });
    } catch (e: any) {
      sendToWeb({ cmd: 'setContent', content: `// Konnte ${path} nicht laden: ${e?.message || e}`, language: 'text', version: 0 });
    }
  }, [projectId, sendToWeb]);

  // Projektwechsel: vorhandene Dateien vom Brain laden.
  useEffect(() => {
    let cancelled = false;
    setLoadErr('');
    brainApi.listProjectFiles(projectId)
      .then(res => {
        if (cancelled) return;
        const paths = (res.files || []).map(f => f.path);
        setServerPaths(paths);
        setCurrentPath(prev => (prev && paths.includes(prev)) ? prev : (paths[0] ?? codeFile.getFiles(projectId)[0]?.path ?? null));
      })
      .catch(e => { if (!cancelled) setLoadErr(String(e?.message || e)); });
    return () => { cancelled = true; };
  }, [projectId]);

  // Live-Updates aus dem Spiegel.
  useEffect(() => {
    return codeFile.subscribe((u) => {
      if ((u.projectId || '') !== (projectId || '')) return;
      setServerPaths(prev => prev.includes(u.path) ? prev : [...prev, u.path]);
      if (!currentPathRef.current) { setCurrentPath(u.path); return; }
      if (u.path !== currentPathRef.current || !readyRef.current) return;
      if (u.patch) {
        sendToWeb({ cmd: 'applyPatch', from: u.patch.from, to: u.patch.to, insert: u.patch.insert, version: u.version });
      } else {
        sendToWeb({ cmd: 'setContent', content: u.content ?? '', language: u.language, version: u.version });
      }
    });
  }, [projectId, sendToWeb]);

  // Datei-Auswahl gewechselt → laden (falls WebView bereit).
  useEffect(() => {
    if (readyRef.current) loadFileIntoEditor(currentPath);
  }, [currentPath, loadFileIntoEditor]);

  const onMessage = useCallback((e: WebViewMessageEvent) => {
    let m: any;
    try { m = JSON.parse(e.nativeEvent.data); } catch { return; }
    if (m.event === 'ready') {
      readyRef.current = true;
      loadFileIntoEditor(currentPathRef.current);
    } else if (m.event === 'onEditFromUser') {
      const path = currentPathRef.current;
      if (!path) return;
      codeFile.sendEdit(projectId, path, { from: m.from, to: m.to, insert: m.insert }, m.fullText, m.version);
    }
  }, [projectId, loadFileIntoEditor]);

  return (
    <View style={styles.container}>
      <View style={styles.tabsRow}>
        {files.length === 0 ? (
          <Text style={styles.noFiles}>{loadErr ? `Fehler: ${loadErr}` : 'Noch keine Datei in diesem Projekt'}</Text>
        ) : (
          <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.tabs}>
            {files.map((path) => {
              const active = path === currentPath;
              const name = path.split('/').pop() || path;
              return (
                <TouchableOpacity key={path} onPress={() => setCurrentPath(path)} style={[styles.tab, active && styles.tabActive]}>
                  <Text style={[styles.tabText, active && styles.tabTextActive]} numberOfLines={1}>{name}</Text>
                </TouchableOpacity>
              );
            })}
          </ScrollView>
        )}
      </View>
      <WebView
        ref={webRef}
        style={styles.web}
        originWhitelist={['*']}
        source={{ html: EDITOR_HTML, baseUrl: '' }}
        onMessage={onMessage}
        javaScriptEnabled
        domStorageEnabled
        keyboardDisplayRequiresUserAction={false}
        androidLayerType="hardware"
        setBuiltInZoomControls={false}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#0D0D1A' },
  tabsRow: { height: 40, backgroundColor: '#12122A', borderBottomColor: '#1E1E2E', borderBottomWidth: 1, justifyContent: 'center' },
  tabs: { alignItems: 'center', paddingHorizontal: 6 },
  noFiles: { color: '#9090B0', fontSize: 13, paddingHorizontal: 12 },
  tab: { paddingHorizontal: 12, paddingVertical: 6, marginHorizontal: 3, borderRadius: 12, backgroundColor: '#0D0D1A', maxWidth: 180 },
  tabActive: { backgroundColor: '#0096FF' },
  tabText: { color: '#9090B0', fontSize: 12, fontWeight: '600' },
  tabTextActive: { color: '#FFFFFF' },
  web: { flex: 1, backgroundColor: '#0D0D1A' },
});

export default CodeEditorTile;
