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

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

const editorHost = ref<HTMLDivElement | null>(null)
let monaco: any = null
let editor: any = null
const expanded = ref(false)
const message = useMessage()

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

// 根据canEdit判断是否为只读模式（统一逻辑）
const isReadOnly = computed(() => !props.canEdit)

// 根据df.options确定语言类型
const getLanguage = () => {
  const languageMap: Record<string, string> = {
    'Javascript': 'javascript',
    'JS': 'javascript',
    'Python': 'python',
    'Py': 'python',
    'PythonExpression': 'python',
    'HTML': 'html',
    'CSS': 'css',
    'Markdown': 'markdown',
    'SCSS': 'scss',
    'JSON': 'json',
    'Golang': 'go',
    'Go': 'go',
    'Jinja': 'html'
  }
  return languageMap[props.df.options] || 'text'
}


async function mountEditor() {
  if (!editorHost.value) return
  
  // 只读模式不需要 Monaco 编辑器
  if (isReadOnly.value) return
  
  if (!monaco) monaco = await loader.init()
  if (editor) return
  
  const language = getLanguage()
  const initialValue = String(props.record[props.df.fieldname] || '')
  
  editor = monaco.editor.create(editorHost.value, {
    value: initialValue,
    language: language,
    automaticLayout: true,
    folding: true,
    minimap: { enabled: false },
    readOnly: false, // 只读模式不会到这里
    wordWrap: props.df.wrap ? 'on' : 'off',
    wordWrapColumn: 120,
    wrappingStrategy: 'advanced',
    scrollBeyondLastLine: false,
    scrollBeyondLastColumn: 0,
    scrollbar: { 
      horizontal: 'auto', 
      vertical: 'auto', 
      horizontalScrollbarSize: 6, 
      verticalScrollbarSize: 6, 
      alwaysConsumeMouseWheel: false 
    },
    theme: 'vs',
    showPrintMargin: false,
    fontSize: 14,
    lineNumbers: 'on',
    renderWhitespace: 'selection',
    tabSize: 2,
    insertSpaces: true
  })
  
  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())
}

function copyToClipboard() {
  // 优先从编辑器获取当前内容，如果没有编辑器则从record获取
  const code = editor ? editor.getValue() : String(props.record[props.df.fieldname] || '')
  if (code) {
    navigator.clipboard.writeText(code).then(() => {
      message.success('代码已复制到剪贴板')
    }).catch((err) => {
      console.error('复制失败:', err)
      // 降级方案：使用传统的复制方法
      fallbackCopyToClipboard(code)
    })
  } else {
    message.warning('没有内容可复制')
  }
}

// 降级复制方案
function fallbackCopyToClipboard(text: string) {
  const textArea = document.createElement('textarea')
  textArea.value = text
  textArea.style.position = 'fixed'
  textArea.style.left = '-999999px'
  textArea.style.top = '-999999px'
  document.body.appendChild(textArea)
  textArea.focus()
  textArea.select()
  
  try {
    document.execCommand('copy')
    message.success('代码已复制到剪贴板')
  } catch (err) {
    console.error('复制失败:', err)
    message.error('复制失败，请手动复制')
  }
  
  document.body.removeChild(textArea)
}

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

onMounted(async () => {
  // 直接创建编辑器
  await nextTick()
  await mountEditor()
  nextTick(() => editor?.layout())
})

onBeforeUnmount(disposeEditor)
</script>

<template>
  <div :class="['field-wrapper', `layout-${labelLayout}`]">
    <label class="field-label">
      {{ ctx.t(df.label || df.fieldname) }}
      <span v-if="df.reqd" class="required">*</span>
    </label>
    <div class="code-editor">
      <div class="code-editor__monaco-wrap" :class="{ collapsed: !expanded, readonly: isReadOnly }">
        <!-- 只读模式：简单代码预览 -->
        <div v-if="isReadOnly" class="code-editor__preview">
          <pre><code>{{ record[df.fieldname] || '' }}</code></pre>
        </div>
        <!-- 编辑模式：Monaco 编辑器 -->
        <div v-else ref="editorHost" class="code-editor__monaco-host"></div>
        <button class="code-editor__copy-btn" type="button" @click="copyToClipboard" :aria-label="ctx.t('Copy')">
          <!-- 轻量复制图标 -->
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M16 1H4C2.9 1 2 1.9 2 3V17H4V3H16V1ZM19 5H8C6.9 5 6 5.9 6 7V21C6 22.1 6.9 23 8 23H19C20.1 23 21 22.1 21 21V7C21 5.9 20.1 5 19 5ZM19 21H8V7H19V21Z" fill="currentColor"/>
          </svg>
        </button>
      </div>
      <div class="code-editor__footer">
        <n-button v-if="!isReadOnly" size="tiny" quaternary @click="toggleExpand">{{ expanded ? ctx.t('Collapse') : ctx.t('Expand') }}</n-button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.field-wrapper :deep(.code-editor) {
  flex: 1;
}

.code-editor { 
  width: 100%; 
  display: grid; 
  grid-template-rows: 1fr auto; 
  gap: 6px; 
}

.code-editor__footer {
  display: flex;
  justify-content: flex-start;
}

.code-editor__monaco-wrap {
  position: relative;
  width: 100%;
  border: 1px solid #e2e8f0;
  border-radius: 10px; /* 更柔和的未来感圆角 */
  overflow: hidden;
  background: #ffffff;
}

.code-editor__monaco-wrap.collapsed { 
  height: auto; 
}

.code-editor__monaco-wrap:not(.collapsed) { 
  height: auto; 
}

/* 只读模式样式 */
.code-editor__monaco-wrap.readonly {
  background: #f8fafc; /* 轻微的背景色 */
  border-color: #e2e8f0;
}

.code-editor__monaco-host {
  width: 100%;
  height: 100%;
}

.code-editor__preview {
  width: 100%;
  height: 100%;
  padding: 12px;
  overflow: auto;
}

.code-editor__preview pre {
  margin: 0;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 14px;
  line-height: 1.5;
  color: #334155;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.code-editor__copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.9);
  color: #64748b; /* slate-500 */
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(8px);
  transition: all 0.15s ease;
  opacity: 0.7;
}

.code-editor__copy-btn:hover {
  background: rgba(255, 255, 255, 0.95);
  color: #334155; /* slate-700 */
  opacity: 1;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.code-editor__copy-btn:active {
  transform: translateY(0);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* Monaco 编辑器样式优化 */
: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>


