<script setup>
import { buildCalloutOpenerLine } from '../../lib/markdown-callout.js'
import ProseCallout from './ProseCallout.vue'
import ContentMarkdownEditableInline from './ContentMarkdownEditableInline.vue'

const props = defineProps({
  /** 콜아웃 본문 */
  modelValue: {
    type: String,
    default: ''
  },
  calloutEmojiEnabled: {
    type: Boolean,
    default: true
  },
  calloutEmoji: {
    type: String,
    default: '💡'
  },
  calloutBackground: {
    type: String,
    default: 'blue'
  },
  /** 본문 첫 줄 source-line(0-based) */
  bodySourceLine: {
    type: Number,
    required: true
  },
  /** 콜아웃 선언 줄 source-line(0-based) */
  blockSourceLine: {
    type: Number,
    required: true
  }
})

const emit = defineEmits(['commit', 'delete-line', 'insert-below', 'merge-with-previous', 'leave-block', 'focus-line'])

const bodyLines = computed(() => {
  const lines = String(props.modelValue ?? '').replace(/\r/g, '').split('\n')
  return lines.length ? lines : ['']
})

const bodyLineEntries = computed(() => bodyLines.value.map((text, index) => ({
  text,
  index,
  sourceLine: props.bodySourceLine + index
})))

/**
 * 콜아웃 마크다운 줄을 반영한다.
 * @param {string[]} contentLines - 본문 줄
 * @returns {void}
 */
const commitCalloutLines = (contentLines) => {
  emit('commit', [
    buildCalloutOpenerLine({
      calloutEmojiEnabled: props.calloutEmojiEnabled,
      calloutEmoji: props.calloutEmoji,
      calloutBackground: props.calloutBackground
    }),
    ...contentLines,
    ':::'
  ])
}

/**
 * 인라인 편집 값을 문자열로 정규화한다.
 * @param {string|{ value?: string }} payload - 편집 페이로드
 * @returns {string} 편집 값
 */
const normalizeInlineValue = (payload) => {
  if (typeof payload === 'string') {
    return payload
  }

  return String(payload?.value ?? '')
}

/**
 * 아래 줄 삽입 페이로드를 정규화한다.
 * @param {string|Object} payload - 아래 줄 삽입 페이로드
 * @returns {{ value: string, before: string, after: string, caretAtStart: boolean }}
 */
const normalizeInsertPayload = (payload) => {
  if (typeof payload === 'string') {
    return {
      value: payload,
      before: '',
      after: '',
      caretAtStart: false
    }
  }

  return {
    value: String(payload?.value ?? ''),
    before: String(payload?.before ?? ''),
    after: String(payload?.after ?? ''),
    caretAtStart: payload?.caretAtStart === true
  }
}

/**
 * 지정한 콜아웃 본문 줄에 포커스를 요청한다.
 * @param {number} sourceLine - 원본 줄 번호
 * @returns {void}
 */
const focusCalloutLine = (sourceLine) => {
  emit('focus-line', {
    line: sourceLine,
    position: 'start',
    offset: 0
  })
}

/**
 * 본문 한 줄 편집 반영
 * @param {number} lineIndex - 본문 줄 인덱스
 * @param {string|{ value?: string }} payload - 편집 페이로드
 * @returns {void}
 */
const onBodyLineCommit = (lineIndex, payload) => {
  const nextLines = [...bodyLines.value]
  nextLines[lineIndex] = normalizeInlineValue(payload)
  commitCalloutLines(nextLines)
}

/**
 * 현재 줄 아래에 콜아웃 본문 줄을 추가한다.
 * @param {number} lineIndex - 본문 줄 인덱스
 * @param {Object|string} payload - 아래 줄 삽입 페이로드
 * @returns {void}
 */
const onBodyLineInsertBelow = (lineIndex, payload) => {
  const { value, before, after, caretAtStart } = normalizeInsertPayload(payload)
  const nextLines = [...bodyLines.value]

  if (caretAtStart && after.length) {
    nextLines[lineIndex] = after
    nextLines.splice(lineIndex, 0, '')
    focusCalloutLine(props.bodySourceLine + lineIndex)
    commitCalloutLines(nextLines)
    return
  }

  if (before.length && after.length) {
    nextLines[lineIndex] = before
    nextLines.splice(lineIndex + 1, 0, after)
    focusCalloutLine(props.bodySourceLine + lineIndex + 1)
    commitCalloutLines(nextLines)
    return
  }

  nextLines[lineIndex] = value
  nextLines.splice(lineIndex + 1, 0, '')
  focusCalloutLine(props.bodySourceLine + lineIndex + 1)
  commitCalloutLines(nextLines)
}
</script>

<template>
  <div
    class="content-markdown-callout-editor relative"
    :data-source-line="blockSourceLine"
  >
    <ProseCallout
      :emoji-enabled="false"
      :background="calloutBackground"
    >
      <div class="content-markdown-callout-editor__inner flex items-start gap-2">
        <span
          class="content-markdown-callout-editor__emoji inline-flex size-9 shrink-0 items-center justify-center rounded-md text-xl text-[var(--site-text)]"
          aria-hidden="true"
        >
          <span v-if="calloutEmojiEnabled">{{ calloutEmoji || '💡' }}</span>
          <span v-else class="text-base text-[#8e9cac]">+</span>
        </span>
        <div class="content-markdown-callout-editor__body-lines min-w-0 flex-1">
          <ContentMarkdownEditableInline
            v-for="line in bodyLineEntries"
            :key="`${blockSourceLine}-callout-line-${line.sourceLine}`"
            block-class="content-markdown-callout-editor__body min-w-0 text-[15px] leading-8 text-[var(--site-text)]"
            enter-mode="insert-below"
            :source-line="line.sourceLine"
            :model-value="line.text"
            @commit="onBodyLineCommit(line.index, $event)"
            @delete-line="emit('delete-line', $event)"
            @insert-below="onBodyLineInsertBelow(line.index, $event)"
            @merge-with-previous="emit('merge-with-previous', line.sourceLine, $event)"
            @leave-block="emit('leave-block', $event)"
          />
        </div>
      </div>
    </ProseCallout>
  </div>
</template>
