<script setup lang="ts">
import type { BlockData } from '@vigilkids/section-core'

import { safeColor } from '@vigilkids/section-core'

import { computed } from 'vue'

const props = defineProps<{
  blockOrder: string[]
  blocks: Record<string, BlockData>
  editorMode?: boolean
  settings: Record<string, unknown>
}>()

const s = computed(() => props.settings)

const maxWidthClass = computed(() => {
  const map: Record<string, string> = {
    full: 'max-w-none',
    prose: 'max-w-prose',
    wide: 'max-w-screen-lg',
  }
  return map[String(s.value.max_width ?? 'prose')] ?? 'max-w-prose'
})

const paddingClass = computed(() => {
  const map: Record<string, string> = {
    compact: 'py-8',
    none: 'py-0',
    standard: 'py-16',
  }
  return map[String(s.value.padding ?? 'none')] ?? 'py-0'
})

/** 将 ProseMirror JSON 或 HTML 字符串转为渲染 HTML */
const renderedContent = computed(() => {
  const content = s.value.content
  if (typeof content === 'string')
    return content
  if (content && typeof content === 'object') {
    return renderProseMirrorBasic(content as ProseMirrorDoc)
  }
  return ''
})

/** ProseMirror 节点类型 */
interface ProseMirrorNode {
  attrs?: Record<string, unknown>
  content?: ProseMirrorNode[]
  marks?: Array<{ attrs?: Record<string, unknown>, type: string }>
  text?: string
  type: string
}

/** ProseMirror 文档根节点 */
interface ProseMirrorDoc {
  content?: ProseMirrorNode[]
  type: 'doc'
}

/** 基础 ProseMirror JSON → HTML 转换 */
function renderProseMirrorBasic(doc: ProseMirrorDoc): string {
  if (!doc.content)
    return ''
  return doc.content.map(renderNode).join('')
}

function renderNode(node: ProseMirrorNode): string {
  switch (node.type) {
    case 'blockquote':
      return `<blockquote>${renderChildren(node)}</blockquote>`
    case 'bulletList':
      return `<ul>${renderChildren(node)}</ul>`
    case 'codeBlock':
      return `<pre><code>${renderChildren(node)}</code></pre>`
    case 'hardBreak':
      return '<br />'
    case 'heading': {
      const level = (node.attrs?.level as number) ?? 2
      return `<h${level}>${renderChildren(node)}</h${level}>`
    }
    case 'horizontalRule':
      return '<hr />'
    case 'listItem':
      return `<li>${renderChildren(node)}</li>`
    case 'orderedList':
      return `<ol>${renderChildren(node)}</ol>`
    case 'paragraph':
      return `<p>${renderChildren(node)}</p>`
    case 'text':
      return applyMarks(node.text ?? '', node.marks)
    default:
      return renderChildren(node)
  }
}

function renderChildren(node: ProseMirrorNode): string {
  if (!node.content)
    return node.text ?? ''
  return node.content.map(renderNode).join('')
}

function applyMarks(text: string, marks?: ProseMirrorNode['marks']): string {
  if (!marks)
    return text
  let result = text
  for (const mark of marks) {
    switch (mark.type) {
      case 'bold':
        result = `<strong>${result}</strong>`
        break
      case 'code':
        result = `<code>${result}</code>`
        break
      case 'italic':
        result = `<em>${result}</em>`
        break
      case 'link':
        result = `<a href="${mark.attrs?.href ?? '#'}">${result}</a>`
        break
    }
  }
  return result
}
</script>

<template>
  <article
    class="px-6"
    :class="paddingClass"
    :style="{ backgroundColor: safeColor(String(s.bg_color ?? '#ffffff')) }"
  >
    <div class="prose prose-lg mx-auto" :class="maxWidthClass" v-html="renderedContent" />
  </article>
</template>
