<script setup>
import { useNamespace } from "@yh-ui/hooks";
import { ref, onMounted, onBeforeUnmount, watch, computed, nextTick } from "vue";
import { aiCodeEditorProps, aiCodeEditorEmits } from "./ai-code-editor";
import { useComponentTheme } from "@yh-ui/theme";
defineOptions({ name: "YhAiCodeEditor" });
const props = defineProps(aiCodeEditorProps);
const emit = defineEmits(aiCodeEditorEmits);
const ns = useNamespace("ai-code-editor");
const { themeStyle } = useComponentTheme("ai-code-editor", props.themeOverrides);
let monaco = null;
const editorRef = ref();
let editor = null;
let isApplyingValue = false;
const editorHeight = computed(() => {
  if (typeof props.height === "number") return `${props.height}px`;
  return props.height;
});
const safeSetValue = (value) => {
  if (!editor) return;
  isApplyingValue = true;
  editor.setValue(value);
  nextTick(() => {
    isApplyingValue = false;
  });
};
const getTargetValue = () => {
  return (props.initialValue !== void 0 && props.initialValue !== null ? props.initialValue : props.modelValue) ?? "";
};
const createEditor = () => {
  if (!editorRef.value) return;
  const container = editorRef.value;
  const targetValue = getTargetValue();
  const containerWidth = container.clientWidth || container.offsetWidth || 800;
  const containerHeight = container.clientHeight || container.offsetHeight || (typeof props.height === "number" ? props.height : 300);
  if (!monaco) return;
  editor = monaco.editor.create(container, {
    value: targetValue,
    language: props.language,
    theme: props.theme,
    readOnly: props.readonly,
    minimap: { enabled: props.minimap },
    wordWrap: props.wordWrap,
    fontSize: props.fontSize,
    tabSize: props.tabSize,
    // 禁用 automaticLayout，改由我们显式控制，避免 Monaco 自身定时读到 0
    automaticLayout: false,
    scrollBeyondLastLine: false,
    lineNumbers: "on",
    renderLineHighlight: "line",
    selectOnLineNumbers: true,
    folding: true,
    lineDecorationsWidth: 10,
    lineNumbersMinChars: 3,
    padding: { top: 12, bottom: 12 },
    scrollbar: {
      vertical: "auto",
      horizontal: "auto",
      useShadows: false,
      verticalScrollbarSize: 10,
      horizontalScrollbarSize: 10
    },
    overviewRulerBorder: false,
    hideCursorInOverviewRuler: true,
    renderWhitespace: "selection"
  });
  editor.layout({ width: containerWidth, height: containerHeight });
  editor.onDidChangeModelContent(() => {
    if (isApplyingValue) return;
    const value = editor?.getValue() ?? "";
    emit("update:modelValue", value);
    emit("change", value);
  });
  if (props.autofocus) {
    editor.focus();
  }
  emit("mount");
};
const forceLayout = () => {
  if (!editor || !editorRef.value) return;
  const w = editorRef.value.clientWidth || editorRef.value.offsetWidth || 800;
  const h = editorRef.value.clientHeight || editorRef.value.offsetHeight || (typeof props.height === "number" ? props.height : 300);
  editor.layout({ width: w, height: h });
  editor.render(true);
};
let resizeObserver = null;
onMounted(async () => {
  if (typeof window !== "undefined") {
    try {
      monaco = await import("monaco-editor");
      await import("monaco-editor/min/vs/editor/editor.main.css");
      if (!self.MonacoEnvironment) {
        const [
          { default: EditorWorker },
          { default: JsonWorker },
          { default: CssWorker },
          { default: HtmlWorker },
          { default: TsWorker }
        ] = await Promise.all([
          import("monaco-editor/esm/vs/editor/editor.worker?worker"),
          import("monaco-editor/esm/vs/language/json/json.worker?worker"),
          import("monaco-editor/esm/vs/language/css/css.worker?worker"),
          import("monaco-editor/esm/vs/language/html/html.worker?worker"),
          import("monaco-editor/esm/vs/language/typescript/ts.worker?worker")
        ]);
        self.MonacoEnvironment = {
          getWorker(_workerId, label) {
            if (label === "json") return new JsonWorker();
            if (label === "css" || label === "scss" || label === "less") return new CssWorker();
            if (label === "html" || label === "handlebars" || label === "razor")
              return new HtmlWorker();
            if (label === "typescript" || label === "javascript") return new TsWorker();
            return new EditorWorker();
          }
        };
      }
    } catch (err) {
      console.error(
        '[YhAiCodeEditor] \u65E0\u6CD5\u52A0\u8F7D monaco-editor\u3002\u5982\u679C\u9700\u8981\u4F7F\u7528\u4EE3\u7801\u7F16\u8F91\u5668\u529F\u80FD\uFF0C\u8BF7\u5728\u60A8\u7684\u9879\u76EE\u4E2D\u5B89\u88C5 "monaco-editor" \u4F9D\u8D56\u3002',
        err
      );
      return;
    }
  }
  nextTick(() => {
    requestAnimationFrame(() => {
      createEditor();
      forceLayout();
      requestAnimationFrame(() => {
        forceLayout();
        if (editorRef.value && typeof ResizeObserver !== "undefined") {
          resizeObserver = new ResizeObserver(() => {
            forceLayout();
          });
          resizeObserver.observe(editorRef.value);
        }
      });
    });
  });
});
onBeforeUnmount(() => {
  if (resizeObserver) {
    resizeObserver.disconnect();
    resizeObserver = null;
  }
  if (editor) {
    emit("dispose");
    editor.dispose();
    editor = null;
  }
});
watch(
  () => props.modelValue,
  (newValue) => {
    if (editor && newValue !== editor.getValue()) {
      safeSetValue(newValue ?? "");
    }
  }
);
watch(
  () => props.language,
  (newLanguage) => {
    if (editor && monaco) {
      const model = editor.getModel();
      if (model) monaco.editor.setModelLanguage(model, newLanguage);
    }
  }
);
watch(
  () => props.theme,
  (newTheme) => {
    if (monaco) {
      monaco.editor.setTheme(newTheme);
    }
  }
);
watch(
  () => props.readonly,
  (newReadonly) => {
    if (editor) {
      editor.updateOptions({ readOnly: newReadonly });
    }
  }
);
const getEditor = () => editor;
const focus = () => editor?.focus();
const setValue = (value) => {
  if (editor) safeSetValue(value);
};
const getValue = () => editor?.getValue() || "";
defineExpose({
  getEditor,
  focus,
  setValue,
  getValue
});
</script>

<template>
  <div :class="ns.b()" :style="themeStyle">
    <div ref="editorRef" :class="ns.e('container')" :style="{
  height: editorHeight
}" />
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-ai-code-editor {
  display: block;
  border: 1px solid var(--yh-border-color);
  border-radius: var(--yh-radius-md);
  overflow: hidden;
}
.yh-ai-code-editor__container {
  width: 100%;
}
.yh-ai-code-editor__container .monaco-editor {
  width: 100% !important;
  height: 100% !important;
}
.yh-ai-code-editor__container .monaco-editor .overflow-guard {
  width: 100% !important;
  height: 100% !important;
}
.yh-ai-code-editor__container .monaco-editor-background,
.yh-ai-code-editor__container .monaco-editor .margin,
.yh-ai-code-editor__container .monaco-editor .inputarea.ime-input {
  background: transparent;
}
</style>
