<template>
  <div class="code-editor" :style="{ height: height }">
    <div class="editor-wrapper">
      <div class="editor-header">
        <span class="file-type">
          <el-icon :class="iconClass">
            <component :is="iconComponent" />
          </el-icon>
          {{ languageLabel }}
        </span>
        <div class="header-actions">
          <el-button size="small" :icon="DocumentCopy" @click="handleCopy">
            {{ t('复制') }}
          </el-button>
          <el-button
            v-if="language === 'json'"
            size="small"
            :icon="MagicStick"
            @click="handleFormat"
            :disabled="!isValidJson"
          >
            {{ t('格式化') }}
          </el-button>
        </div>
      </div>
      <Codemirror
        v-model="localValue"
        :style="{ height: editorHeight }"
        :extensions="extensions"
        :autofocus="autofocus"
        :indent-with-tab="true"
        :tab-size="2"
        :placeholder="placeholder"
        @change="handleChange"
      />
      <div v-if="language === 'json'" v-show="!isValidJson && modelValue" class="validation-error">
        <el-icon>
          <WarningFilled />
        </el-icon>
        JSON 格式错误
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, markRaw, type Component } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { json } from '@codemirror/lang-json'
import { EditorView } from '@codemirror/view'
import { Document, DocumentCopy, MagicStick, Monitor, WarningFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'

const { t } = useI18n({ useScope: 'global' })

type LanguageType = 'json' | 'bash'

interface Props {
  modelValue: string
  language?: LanguageType
  height?: string
  autofocus?: boolean
  placeholder?: string
  readonly?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  language: 'json',
  height: '200px',
  autofocus: false,
  placeholder: '',
  readonly: false
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>()

const localValue = ref(props.modelValue)

// Language-specific configurations
const languageConfig = computed(() => {
  const configs: Record<LanguageType, { label: string; icon: Component; iconColor: string }> = {
    json: {
      label: 'JSON',
      icon: markRaw(Document),
      iconColor: '#e6a23c' // orange
    },
    bash: {
      label: 'Bash Script',
      icon: markRaw(Monitor),
      iconColor: '#67c23a' // green
    }
  }
  return configs[props.language]
})

const languageLabel = computed(() => languageConfig.value.label)
const iconComponent = computed(() => languageConfig.value.icon)
const iconClass = computed(() => `icon-${props.language}`)

// Calculate editor height (minus header and potential error)
const editorHeight = computed(() => {
  const totalHeight = parseInt(props.height)
  return `${totalHeight - 32}px`
})

// Watch for external changes
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal !== localValue.value) {
      localValue.value = newVal
    }
  }
)

// Editor extensions - using Codemirror default styles
const extensions = computed(() => {
  const exts: any[] = [EditorView.lineWrapping]

  // Add language-specific syntax highlighting
  if (props.language === 'json') {
    exts.push(json())
  }

  // Add readonly mode
  if (props.readonly) {
    exts.push(EditorView.editable.of(false))
  }

  return exts
})

// Check if current value is valid JSON (only for JSON mode)
const isValidJson = computed(() => {
  if (props.language !== 'json') return true
  if (!localValue.value || !localValue.value.trim()) {
    return true // Empty is considered valid
  }
  try {
    JSON.parse(localValue.value)
    return true
  } catch {
    return false
  }
})

// Handle value change
function handleChange(value: string) {
  localValue.value = value
  emit('update:modelValue', value)
}

// Copy to clipboard
async function handleCopy() {
  if (!localValue.value) return

  try {
    await navigator.clipboard.writeText(localValue.value)
    ElMessage.success(t('已复制到剪贴板'))
  } catch {
    ElMessage.error(t('复制失败'))
  }
}

// Format JSON (only for JSON mode)
function handleFormat() {
  if (props.language !== 'json') return
  if (!localValue.value || !localValue.value.trim()) return

  try {
    const parsed = JSON.parse(localValue.value)
    const formatted = JSON.stringify(parsed, null, 2)
    localValue.value = formatted
    emit('update:modelValue', formatted)
  } catch {
    // Already showing error, do nothing
  }
}

// Expose methods
defineExpose({
  format: handleFormat,
  isValid: isValidJson,
  getValue: () => localValue.value,
  setValue: (val: string) => {
    localValue.value = val
    emit('update:modelValue', val)
  }
})
</script>

<style lang="scss" scoped>
.code-editor {
  width: 100%;
  overflow: hidden;
}

.editor-wrapper {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  border: 1px solid #dcdfe6;
}

.editor-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 32px;
  padding: 0 8px;
  background-color: #f5f7fa;

  border-bottom: 1px solid #dcdfe6;
  // border-bottom: none;
  // border-radius: 4px 4px 0 0;

  .file-type {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: #909399;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    .el-icon {
      font-size: 14px;
    }

    .icon-json {
      color: #e6a23c;
    }

    .icon-bash {
      color: #67c23a;
    }
  }

  .header-actions {
    display: flex;
    gap: 8px;

    .el-button {
      background-color: transparent;
      border-color: #dcdfe6;
      color: #606266;

      &:hover:not(:disabled) {
        background-color: #ecf5ff;
        border-color: #c6e2ff;
        color: #409eff;
      }

      &:disabled {
        opacity: 0.5;
      }
    }
  }
}

.validation-error {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  color: #f56c6c;
  font-size: 12px;
  background-color: #fef0f0;
  border: 1px solid #dcdfe6;
  border-top: none;
  border-radius: 0 0 4px 4px;

  .el-icon {
    font-size: 14px;
  }
}

:deep(.cm-editor) {
  flex: 1;
  min-height: 0;
}

:deep(.cm-scroller) {
  overflow: auto;
}
</style>
