<template>
  <v-dialog v-model="visible" fullscreen transition="dialog-bottom-transition">
    <v-card>
      <!-- Toolbar -->
      <v-toolbar density="compact" color="surface">
        <v-btn icon="mdi-close" @click="requestClose" />
        <v-toolbar-title class="text-body-2">
          {{ fileName }}
          <span v-if="modified" class="text-error ml-1">●</span>
        </v-toolbar-title>
        <v-spacer />
        <v-chip size="x-small" variant="tonal" label class="mr-2">{{ language }}</v-chip>
        <v-btn size="small" variant="tonal" prepend-icon="mdi-content-save" @click="save" :loading="saving" :disabled="!modified">
          保存
        </v-btn>
        <v-btn size="small" variant="text" prepend-icon="mdi-theme-light-dark" @click="toggleTheme" />
      </v-toolbar>

      <!-- Editor container -->
      <div ref="editorContainer" style="height: calc(100vh - 48px); width: 100%;" />

      <!-- Unsaved changes dialog -->
      <v-dialog v-model="showCloseConfirm" max-width="400">
        <v-card border>
          <v-card-title>未保存的更改</v-card-title>
          <v-card-text>文件已修改但未保存，确定要关闭吗？</v-card-text>
          <v-card-actions>
            <v-spacer />
            <v-btn variant="text" @click="showCloseConfirm = false">取消</v-btn>
            <v-btn color="error" variant="flat" @click="forceClose">不保存关闭</v-btn>
            <v-btn color="primary" variant="flat" @click="saveThenClose">保存并关闭</v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </v-card>
  </v-dialog>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick, onBeforeUnmount } from 'vue'
import * as monaco from 'monaco-editor'
import { http } from '@/api'
import { useSnackbar } from '@/composables/useSnackbar'

const snackbar = useSnackbar()

const props = defineProps<{
  modelValue: boolean
  filePath: string
  fileName: string
  fileContent: string
  serverId: number
}>()

const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  saved: []
}>()

const visible = computed({
  get: () => props.modelValue,
  set: (v) => emit('update:modelValue', v),
})

const editorContainer = ref<HTMLElement>()
const saving = ref(false)
const modified = ref(false)
const showCloseConfirm = ref(false)
const language = ref('plaintext')

let editor: monaco.editor.IStandaloneCodeEditor | null = null
let originalContent = ''

// Language detection
const LANG_MAP: Record<string, string> = {
  js: 'javascript', mjs: 'javascript', cjs: 'javascript',
  ts: 'typescript', mts: 'typescript', cts: 'typescript',
  jsx: 'javascript', tsx: 'typescript',
  py: 'python', rb: 'ruby', sh: 'shell', bash: 'shell', zsh: 'shell',
  php: 'php', java: 'java', go: 'go', rs: 'rust', c: 'c', cpp: 'cpp',
  h: 'c', hpp: 'cpp', cs: 'csharp', swift: 'swift', kt: 'kotlin',
  html: 'html', htm: 'html', css: 'css', scss: 'scss', less: 'less',
  json: 'json', xml: 'xml', yaml: 'yaml', yml: 'yaml', toml: 'toml',
  md: 'markdown', sql: 'sql', graphql: 'graphql',
  dockerfile: 'dockerfile', makefile: 'makefile',
  conf: 'ini', ini: 'ini', env: 'ini',
}

function detectLanguage(fileName: string): string {
  const ext = fileName.split('.').pop()?.toLowerCase() || ''
  if (fileName === 'Dockerfile') return 'dockerfile'
  if (fileName === 'Makefile') return 'makefile'
  return LANG_MAP[ext] || 'plaintext'
}

function initEditor() {
  if (!editorContainer.value) return

  language.value = detectLanguage(props.fileName)
  originalContent = props.fileContent
  modified.value = false

  editor = monaco.editor.create(editorContainer.value, {
    value: props.fileContent,
    language: language.value,
    theme: localStorage.getItem('nexus_editor_theme') === 'light' ? 'vs' : 'vs-dark',
    automaticLayout: true,
    lineNumbers: 'on',
    folding: true,
    bracketPairColorization: { enabled: true },
    matchBrackets: 'always',
    fontSize: 14,
    minimap: { enabled: true },
    tabSize: 4,
    wordWrap: 'off',
    scrollBeyondLastLine: false,
    suggestOnTriggerCharacters: true,
  })

  // Track modifications
  editor.onDidChangeModelContent(() => {
    modified.value = editor!.getValue() !== originalContent
  })

  // Ctrl+S to save
  editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
    save()
  })
}

function toggleTheme() {
  const current = localStorage.getItem('nexus_editor_theme') || 'dark'
  const next = current === 'dark' ? 'light' : 'dark'
  localStorage.setItem('nexus_editor_theme', next)
  monaco.editor.setTheme(next === 'light' ? 'vs' : 'vs-dark')
}

async function save() {
  if (!editor || !modified.value) return
  saving.value = true
  try {
    await http.post('/sync/write-file', {
      server_id: props.serverId,
      path: props.filePath,
      content: editor.getValue(),
    })
    originalContent = editor.getValue()
    modified.value = false
    snackbar('文件已保存')
    emit('saved')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '保存失败'
    snackbar(msg, 'error')
  } finally {
    saving.value = false
  }
}

function requestClose() {
  if (modified.value) {
    showCloseConfirm.value = true
  } else {
    close()
  }
}

function forceClose() {
  showCloseConfirm.value = false
  close()
}

async function saveThenClose() {
  await save()
  showCloseConfirm.value = false
  close()
}

function close() {
  if (editor) {
    editor.dispose()
    editor = null
  }
  visible.value = false
}

// Initialize editor when dialog opens
watch(visible, async (v) => {
  if (v) {
    await nextTick()
    initEditor()
  } else if (editor) {
    editor.dispose()
    editor = null
  }
})

onBeforeUnmount(() => {
  if (editor) {
    editor.dispose()
    editor = null
  }
})
</script>
