<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick, computed } from 'vue'
import loader from '@monaco-editor/loader'
import { marked } from 'marked'

const props = defineProps<{ df: any; record: Record<string, any>; canEdit: boolean; ctx: any }>()

// Label布局：上下结构(vertical) 或 左右结构(horizontal)
const labelLayout = computed(() => props.df.label_layout || 'vertical')

const editorHost = ref<HTMLDivElement | null>(null)
let monaco: any = null
let editor: any = null
const expanded = ref(false)
const mode = ref<'preview' | 'edit'>('preview')

const mdPreview = computed(() => {
  try {
    return marked.parse(String(props.record[props.df.fieldname] || '')) as string
  } catch {
    return String(props.record[props.df.fieldname] || '')
  }
})

async function mountEditor() {
  if (!editorHost.value) return
  if (!monaco) monaco = await loader.init()
  if (editor) return
  editor = monaco.editor.create(editorHost.value, {
    value: String(props.record[props.df.fieldname] || ''),
    language: 'markdown',
    automaticLayout: true,
    folding: true,
    minimap: { enabled: false },
    readOnly: !props.canEdit,
    wordWrap: 'on',
    wordWrapColumn: 120,
    wrappingStrategy: 'advanced',
    scrollBeyondLastLine: false,
    scrollBeyondLastColumn: 0,
    scrollbar: { horizontal: 'hidden', vertical: 'auto', horizontalScrollbarSize: 6, verticalScrollbarSize: 6, alwaysConsumeMouseWheel: false },
  })
  const refreshBars = () => {
    if (!editor || !editorHost.value) return
    const info = editor.getLayoutInfo()
    const hasV = editor.getScrollHeight() > info.height + 1
    const hasH = editor.getScrollWidth() > info.width + 1
    editorHost.value.classList.toggle('no-scroll-y', !hasV)
    editorHost.value.classList.toggle('no-scroll-x', !hasH)
  }
  refreshBars()
  editor.onDidContentSizeChange(() => refreshBars())
  editor.onDidScrollChange(() => refreshBars())
  editor.onDidLayoutChange(() => refreshBars())
  editor.onDidChangeModelContent(() => {
    if (!editor) return
    props.record[props.df.fieldname] = editor.getValue()
    refreshBars()
  })
}

function disposeEditor() {
  try { editor?.dispose() } catch {}
  editor = null
}

function toggleExpand() {
  expanded.value = !expanded.value
  nextTick(() => editor?.layout())
}

watch(() => props.canEdit, (v) => {
  editor?.updateOptions({ readOnly: !v })
})

watch(() => props.record[props.df.fieldname], (v) => {
  if (editor && v !== editor.getValue()) editor.setValue(String(v || ''))
})

onMounted(() => {
  // 默认预览，不创建编辑器
})

watch(mode, async (m) => {
  if (m === 'edit') {
    await nextTick()
    await mountEditor()
    nextTick(() => editor?.layout())
  } else {
    disposeEditor()
  }
})

onBeforeUnmount(disposeEditor)
</script>

<template>
  <div :class="['field-wrapper', `layout-${labelLayout}`]">
    <label class="field-label">
      {{ ctx?.t ? ctx.t(df.label || df.fieldname) : (df.label || df.fieldname) }}
      <span v-if="df.reqd" class="required">*</span>
    </label>
    <div class="md-editor">
      <div class="md-editor__toolbar">
        <n-button
          v-if="mode==='edit'"
          size="tiny"
          quaternary
          :type="'default'"
          @click="mode='preview'"
        >{{ props.ctx?.t ? props.ctx.t('Preview') : 'Preview' }}</n-button>
        <n-button
          v-else
          size="tiny"
          quaternary
          :type="'default'"
          @click="mode='edit'"
        >{{ props.ctx?.t ? props.ctx.t('Edit') : 'Edit' }}</n-button>
      </div>

      <div v-if="mode==='preview'" class="md-editor__preview" v-html="mdPreview"></div>
      <div v-else ref="editorHost" class="md-editor__monaco" :class="{ collapsed: !expanded }"></div>

      <div v-if="mode==='edit'" class="md-editor__actions">
        <n-button size="tiny" quaternary @click="toggleExpand">{{ expanded ? (props.ctx?.t ? props.ctx.t('Collapse') : 'Collapse') : (props.ctx?.t ? props.ctx.t('Expand') : 'Expand') }}</n-button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.md-editor { width: 100%; display: grid; grid-template-rows: auto 1fr; gap: 6px; }
.md-editor__toolbar { display: flex; }
.md-editor__preview {
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  padding: 12px;
}
.md-editor__monaco {
  width: 100%;
  height: 500px;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
}
.md-editor__monaco.collapsed { height: 500px; }
.md-editor__monaco:not(.collapsed) { height: 800px; }

/* 细化滚动条 */
:deep(.monaco-editor .minimap) { display: none; }
:deep(.monaco-scrollable-element > .scrollbar) { background: transparent !important; opacity: 0.6; }
:deep(.monaco-scrollable-element > .scrollbar:hover) { opacity: 0.9; }
:deep(.monaco-scrollable-element > .scrollbar.vertical) { width: 6px !important; }
:deep(.monaco-scrollable-element > .scrollbar.vertical .slider) { width: 6px !important; background: #cbd5e1 !important; border-radius: 4px !important; }
:deep(.monaco-scrollable-element > .scrollbar.horizontal) { height: 6px !important; }
:deep(.monaco-scrollable-element > .scrollbar.horizontal .slider) { height: 6px !important; background: #cbd5e1 !important; border-radius: 4px !important; }

/* 无溢出隐藏滚动条 */
.no-scroll-y :deep(.monaco-scrollable-element > .scrollbar.vertical) { display: none !important; }
.no-scroll-x :deep(.monaco-scrollable-element > .scrollbar.horizontal) { display: none !important; }
</style>


