<template>
  <div ref="editorRef" class="codemirror-mobile-editor-container" :style="{ fontSize: currentFontSize + 'px', fontFamily: editorFontFamily }"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, shallowRef, computed } from 'vue';
import { EditorState, Compartment } from '@codemirror/state';
import { useAppearanceStore } from '../stores/appearance.store';
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine, drawSelection, dropCursor } from '@codemirror/view';
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language';
import { vscodeDark } from '@uiw/codemirror-theme-vscode';
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands';
import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
import { highlightSelectionMatches, searchKeymap, openSearchPanel } from '@codemirror/search'; // + Import search functionalities

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
  language: {
    type: String,
    default: 'plaintext', 
  },
});

const emit = defineEmits(['update:modelValue', 'request-save']);

const appearanceStore = useAppearanceStore();
const editorRef = ref<HTMLDivElement | null>(null);
const view = shallowRef<EditorView | null>(null);
const languageCompartment = new Compartment();
const currentFontSize = ref(appearanceStore.currentMobileEditorFontSize);
const MIN_FONT_SIZE = 8;
const MAX_FONT_SIZE = 40;
let lastPinchDistance = 0;
const debounceTimeout = ref<number | null>(null);
const DEBOUNCE_DELAY = 500; // 500ms 防抖延迟

const editorFontFamily = computed(() => appearanceStore.currentEditorFontFamily);

const getDistance = (touches: TouchList): number => {
  if (touches.length < 2) return 0;
  const touch1 = touches[0];
  const touch2 = touches[1];
  return Math.sqrt(
    Math.pow(touch2.pageX - touch1.pageX, 2) +
    Math.pow(touch2.pageY - touch1.pageY, 2)
  );
};

const onTouchStart = (event: TouchEvent) => {
  if (editorRef.value && editorRef.value.contains(event.target as Node)) {
    if (event.touches.length === 2) {
      event.preventDefault();
      lastPinchDistance = getDistance(event.touches);
    }
  }
};

const debouncedSetMobileEditorFontSize = (size: number) => {
  if (debounceTimeout.value !== null) {
    clearTimeout(debounceTimeout.value);
  }
  debounceTimeout.value = window.setTimeout(() => {
    appearanceStore.setMobileEditorFontSize(size);
  }, DEBOUNCE_DELAY);
};

const onTouchMove = (event: TouchEvent) => {
  if (editorRef.value && editorRef.value.contains(event.target as Node)) {
    if (event.touches.length === 2) {
      event.preventDefault();
      const newPinchDistance = getDistance(event.touches);
      if (lastPinchDistance > 0 && newPinchDistance > 0) {
        const scale = newPinchDistance / lastPinchDistance;
        let newFontSize = currentFontSize.value * scale;
        newFontSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, newFontSize));
        
        if (Math.abs(currentFontSize.value - newFontSize) > 0.1) { 
            currentFontSize.value = newFontSize;
            debouncedSetMobileEditorFontSize(newFontSize);
        }
      }
      if (newPinchDistance > 0) {
        lastPinchDistance = newPinchDistance;
      } else if (event.touches.length === 2) { 
        lastPinchDistance = getDistance(event.touches);
      }
    }
  }
};

const onTouchEnd = (event: TouchEvent) => {
  if (event.touches.length < 2) {
    lastPinchDistance = 0;
  }
};
const createEditorState = (doc: string, languageExtension: any) => {
  return EditorState.create({
    doc,
    extensions: [
      languageCompartment.of(languageExtension), 
      vscodeDark,
      lineNumbers(), 
      history(),
      highlightActiveLineGutter(),
      foldGutter(), 
      drawSelection(), 
      dropCursor(),
      EditorState.allowMultipleSelections.of(true),
      indentOnInput(), 
      bracketMatching(), 
      highlightActiveLine(),
      closeBrackets(), 
      autocompletion(),
      highlightSelectionMatches(), 
      EditorView.updateListener.of((update) => {
        if (update.docChanged) {
          emit('update:modelValue', update.state.doc.toString());
        }
      }),
      keymap.of([
        ...closeBracketsKeymap,
        ...defaultKeymap,
        ...historyKeymap,
        ...foldKeymap,
        ...searchKeymap, // + Add search keymap
        { key: "Mod-s", run: () => { emit('request-save'); return true; } }
      ]),
    ],
  });
};

const getLanguageExtension = async (lang: string) => {
  if (lang === 'javascript') {
    const { javascript } = await import('@codemirror/lang-javascript');
    return javascript();
  }
  if (lang === 'css') {
    try {
      const cssModule = await import('@codemirror/lang-css');
      if (cssModule && typeof cssModule.css === 'function') {
        const cssExtension = cssModule.css();
        return cssExtension;
      } else {
        return [];
      }
    } catch (error) {
      return [];
    }
  }
  if (lang === 'html') {
    const { html } = await import('@codemirror/lang-html');
    return html();
  }
  if (lang === 'python') {
    const { python } = await import('@codemirror/lang-python');
    return python();
  }
  if (lang === 'java') {
    const { java } = await import('@codemirror/lang-java');
    return java();
  }
  if (lang === 'cpp') {
    const { cpp } = await import('@codemirror/lang-cpp');
    return cpp();
  }
  if (lang === 'php') {
    const { php } = await import('@codemirror/lang-php');
    return php();
  }
  if (lang === 'go') {
    const { go } = await import('@codemirror/lang-go');
    return go();
  }
  if (lang === 'rust') {
    const { rust } = await import('@codemirror/lang-rust');
    return rust();
  }
  if (lang === 'sql') {
    const { sql } = await import('@codemirror/lang-sql');
    return sql();
  }
  if (lang === 'json') {
    const { json } = await import('@codemirror/lang-json');
    return json();
  }
  if (lang === 'yaml') {
    const { yaml } = await import('@codemirror/lang-yaml');
    return yaml();
  }
  if (lang === 'xml') {
    const { xml } = await import('@codemirror/lang-xml');
    return xml();
  }
  if (lang === 'shell' || lang === 'bash') {
    const { StreamLanguage } = await import('@codemirror/language');
    const { shell } = await import('@codemirror/legacy-modes/mode/shell');
    return StreamLanguage.define(shell);
  }
  if (lang === 'markdown') {
    const { markdown, commonmarkLanguage } = await import('@codemirror/lang-markdown');
    const { GFM } = await import('@lezer/markdown');
    return markdown({
        base: commonmarkLanguage, 
        extensions: GFM 
    });
  }
  if (lang === 'typescript' || lang === 'ts' || lang === 'tsx') {
    const { javascript } = await import('@codemirror/lang-javascript');
    return javascript({ typescript: true, jsx: true });
  }
  return [];
};


onMounted(async () => {
  // Initialize font size from store
  currentFontSize.value = appearanceStore.currentMobileEditorFontSize;

  if (editorRef.value) {
    const langExt = await getLanguageExtension(props.language);
    console.log('[CodeMirrorMobileEditor DEBUG] onMounted - Initial language:', props.language, 'Fetched langExt:', langExt);
    const startState = createEditorState(props.modelValue, langExt);
    
    view.value = new EditorView({
      state: startState,
      parent: editorRef.value,
    });
    editorRef.value.addEventListener('touchstart', onTouchStart, { passive: false });
    editorRef.value.addEventListener('touchmove', onTouchMove, { passive: false });
    editorRef.value.addEventListener('touchend', onTouchEnd, { passive: false });
  }
});

onBeforeUnmount(() => {
  if (view.value) {
    view.value.destroy();
    view.value = null;
  }
  if (editorRef.value) {
    editorRef.value.removeEventListener('touchstart', onTouchStart);
    editorRef.value.removeEventListener('touchmove', onTouchMove);
    editorRef.value.removeEventListener('touchend', onTouchEnd);
  }
  if (debounceTimeout.value !== null) {
    clearTimeout(debounceTimeout.value);
  }
});

watch(() => props.modelValue, (newValue) => {
  if (view.value && newValue !== view.value.state.doc.toString()) {
    view.value.dispatch({
      changes: { from: 0, to: view.value.state.doc.length, insert: newValue },
    });
  }
});

watch(() => props.language, async (newLanguage, oldLanguage) => {
  if (view.value && newLanguage !== oldLanguage) {
    const langExt = await getLanguageExtension(newLanguage);
    view.value.dispatch({
      effects: languageCompartment.reconfigure(langExt)
    });
  }
});

watch(() => appearanceStore.currentMobileEditorFontSize, (newSize) => {
  if (newSize !== currentFontSize.value) {
    currentFontSize.value = newSize;
  }
});

const openSearch = () => {
  if (view.value) {
    openSearchPanel(view.value);
  }
};

defineExpose({
  focus: () => view.value?.focus(),
  openSearch, // + Expose openSearch method
});

</script>

<style scoped>
.codemirror-mobile-editor-container {
  width: 100%;
  height: 100%;
  min-height: 200px;
  text-align: left;
  overflow: auto;
}

.codemirror-mobile-editor-container :deep(.cm-gutters) {
  background-color: #1E1E1E !important;
  color: #858585 !important;
  border-right: 1px solid var(--border-color, #cccccc) !important;
}

.codemirror-mobile-editor-container :deep(.cm-selectionBackground) {
  background-color: #5264ac !important;
}
</style>
