<script setup>
import { buildCodeBlockLines } from '../../lib/markdown-code-block.js'
import ContentMarkdownEditableInline from './ContentMarkdownEditableInline.vue'
import ProseCodeBlock from './ProseCodeBlock.vue'

const props = defineProps({
  /** 코드 본문 */
  modelValue: {
    type: String,
    default: ''
  },
  /** 언어(slug) */
  language: {
    type: String,
    default: ''
  },
  /** 줄 번호 표시 */
  showLineNumbers: {
    type: Boolean,
    default: true
  },
  /** 본문 첫 줄 source-line(0-based) */
  bodySourceLine: {
    type: Number,
    required: true
  }
})

const emit = defineEmits(['commit', 'insert-above', 'insert-below', 'delete-line', 'focus-line'])

const languageDraft = ref(props.language)
const lineNumbersEnabled = ref(props.showLineNumbers)
const liveBody = ref(props.modelValue)

watch(() => props.language, (value) => {
  languageDraft.value = value
})

watch(() => props.showLineNumbers, (value) => {
  lineNumbersEnabled.value = value
})

watch(() => props.modelValue, (value) => {
  liveBody.value = value
})

/** @type {import('vue').ComputedRef<string[]>} */
const bodyLines = computed(() => {
  const text = String(liveBody.value ?? '')

  if (!text.length) {
    return ['']
  }

  return text.split('\n')
})

/** @type {import('vue').ComputedRef<number[]>} */
const gutterLines = computed(() => bodyLines.value.map((_, index) => index + 1))

/**
 * 마크다운에 코드 블록을 반영한다.
 * @param {string} body - 본문
 * @returns {void}
 */
const commitCodeBlock = (body) => {
  emit('commit', buildCodeBlockLines({
    language: languageDraft.value,
    showLineNumbers: lineNumbersEnabled.value,
    body
  }))
}

/**
 * 본문 편집 반영
 * @param {string} body - 본문
 * @returns {void}
 */
const onBodyCommit = (body) => {
  liveBody.value = body
  commitCodeBlock(body)
}

/**
 * 입력 중 줄 번호 갱신용 본문 동기화
 * @param {string} body - 본문
 * @returns {void}
 */
const onBodyInput = (body) => {
  liveBody.value = body
  commitCodeBlock(body)
}

/**
 * 코드 블록 아래로 이탈(다음 문단 생성)
 * @param {Object} payload - insert-below 페이로드
 * @returns {void}
 */
const onExitBelow = (payload) => {
  emit('insert-below', payload)
}

/**
 * 언어 입력 반영
 * @returns {void}
 */
const onLanguageCommit = () => {
  commitCodeBlock(props.modelValue)
}

/**
 * 줄 번호 표시를 토글한다.
 * @returns {void}
 */
const toggleLineNumbers = () => {
  lineNumbersEnabled.value = !lineNumbersEnabled.value
  commitCodeBlock(props.modelValue)
}
</script>

<template>
  <ProseCodeBlock
    class="content-markdown-code-block-editor"
    :show-line-numbers="lineNumbersEnabled"
    :line-numbers="gutterLines"
    :data-source-line="bodySourceLine - 1"
    :data-source-line-end="bodySourceLine + bodyLines.length"
  >
    <template #header-tools>
      <div
        class="content-markdown-code-block-editor__toolbar pointer-events-none flex items-center gap-1.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100"
      >
        <button
          class="content-markdown-code-block-editor__line-numbers pointer-events-auto rounded border border-white/15 bg-white/10 px-2 py-0.5 text-xs font-medium text-white/70 transition-colors hover:bg-white/15 hover:text-white"
          type="button"
          :aria-pressed="lineNumbersEnabled"
          :title="lineNumbersEnabled ? '줄 번호 숨기기' : '줄 번호 표시'"
          @mousedown.prevent
          @click="toggleLineNumbers"
        >
          {{ lineNumbersEnabled ? '줄번호' : '줄번호 끔' }}
        </button>
        <input
          v-model="languageDraft"
          class="content-markdown-code-block-editor__language pointer-events-auto w-[7.5rem] rounded border border-white/15 bg-white/10 px-2 py-0.5 text-xs text-white outline-none transition-colors placeholder:text-white/35 focus:border-white/30 focus:bg-white/15"
          type="text"
          placeholder="Language..."
          spellcheck="false"
          @mousedown.stop
          @keydown.stop
          @blur="onLanguageCommit"
          @keydown.enter.prevent="onLanguageCommit"
        >
      </div>
    </template>

    <ContentMarkdownEditableInline
      tag="pre"
      block-class="content-markdown-code-block-editor__editor m-0 min-w-0 border-0 bg-transparent p-0 font-mono text-sm leading-6 text-white outline-none"
      enter-mode="multiline"
      plain-text
      arrow-exit-creates-line
      :source-line="bodySourceLine"
      :source-line-count="bodyLines.length"
      :model-value="modelValue"
      @input="onBodyInput"
      @commit="onBodyCommit"
      @insert-above="emit('insert-above', $event)"
      @insert-below="onExitBelow"
      @delete-line="emit('delete-line', $event)"
      @focus-line="emit('focus-line', $event)"
    />
  </ProseCodeBlock>
</template>

<style scoped>
.content-markdown-code-block-editor :deep(.prose-code-block__content) {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.content-markdown-code-block-editor :deep(.prose-code-block__header) {
  pointer-events: none;
}

.content-markdown-code-block-editor__toolbar {
  pointer-events: none;
}

.content-markdown-code-block-editor__toolbar > * {
  pointer-events: auto;
}
</style>
