import mergedAns from '../merged_ans.json'

const MOCK_DELAY = 80

function wait(delay = MOCK_DELAY) {
  return new Promise((resolve) => {
    window.setTimeout(resolve, delay)
  })
}

function getRawData() {
  return mergedAns?.data || {}
}

function buildOutlineNodes(nodes = []) {
  return nodes
    .filter((node) => node?.semantic_type === 'heading')
    .sort((left, right) => {
      const leftPage = Number(left?.page_idx || 0)
      const rightPage = Number(right?.page_idx || 0)
      if (leftPage !== rightPage) return leftPage - rightPage
      const leftOrder = Number(left?.layout?.reading_order || 0)
      const rightOrder = Number(right?.layout?.reading_order || 0)
      return leftOrder - rightOrder
    })
    .map((node, index) => {
      const contentPayload = node?.content_payload || {}
      return {
        id: node?.node_id || `outline_${index}`,
        title: contentPayload?.text || `章节 ${index + 1}`,
        page_idx: Number(node?.page_idx || 0),
        level: Number(contentPayload?.heading_level || 1),
        children: []
      }
    })
}

function normalizePage(page) {
  return {
    page_idx: Number(page?.page_idx || 0),
    width: Number(page?.width || 0),
    height: Number(page?.height || 0),
    rotation: Number(page?.rotation || 0),
    node_ids: Array.isArray(page?.node_ids) ? page.node_ids : [],
    node_count: Number(page?.node_count || 0),
    has_image: Boolean(page?.has_image),
    has_table: Boolean(page?.has_table)
  }
}

function normalizeNode(node, index = 0) {
  const contentPayload = node?.content_payload || {}
  const semanticType = node?.semantic_type || 'unknown'
  const pageIdx = Number(node?.page_idx || 0)
  const nodeId = node?.node_id || `node_${pageIdx}_${index}`
  const rawText = String(contentPayload?.text || '').trim()
  const blockType = semanticType === 'heading'
    ? 'heading'
    : semanticType === 'table'
      ? 'table'
      : semanticType === 'image'
        ? 'image'
        : semanticType === 'list'
          ? 'list'
          : rawText
            ? 'paragraph'
            : 'empty'

  return {
    node_id: nodeId,
    semantic_type: semanticType,
    page_idx: pageIdx,
    content_payload: contentPayload,
    layout: node?.layout || {},
    style_spans: Array.isArray(node?.style_spans) ? node.style_spans : [],
    block: {
      id: nodeId,
      pageIdx,
      type: blockType,
      semanticType,
      text: rawText,
      level: Number(contentPayload?.heading_level || 0) || null,
      style: contentPayload?.style || {},
      sourceNodeId: nodeId,
      translationNodeId: `${nodeId}__translation`,
      parentId: contentPayload?.parent_id || null,
      order: Number(node?.layout?.reading_order ?? index),
      pageNodeOrder: Number(index),
      isReadOnly: ['image', 'formula'].includes(semanticType),
      children: []
    }
  }
}

function buildBlockModel(nodes = []) {
  const normalizedNodes = nodes.map((node, index) => normalizeNode(node, index))
  const blocks = normalizedNodes.map((node) => node.block)
  const pageMap = normalizedNodes.reduce((acc, node) => {
    const pageIdx = Number(node.page_idx || 0)
    if (!acc[pageIdx]) acc[pageIdx] = []
    acc[pageIdx].push(node.block)
    return acc
  }, {})
  const nodeMap = normalizedNodes.reduce((acc, node) => {
    if (node.node_id) acc[node.node_id] = node.block
    return acc
  }, {})
  const pageNodeMap = normalizedNodes.reduce((acc, node) => {
    const pageIdx = Number(node.page_idx || 0)
    if (!acc[pageIdx]) acc[pageIdx] = []
    acc[pageIdx].push({
      nodeId: node.node_id,
      blockId: node.block.id,
      type: node.block.type,
      semanticType: node.block.semanticType,
      order: node.block.order
    })
    return acc
  }, {})

  return { blocks, pageMap, nodeMap, pageNodeMap }
}

function normalizeEditorNode(node, index) {
  if (!node || typeof node !== 'object') return null
  const type = typeof node.type === 'string' ? node.type : ''
  if (!type) return null
  const attrs = node.attrs && typeof node.attrs === 'object' ? node.attrs : {}
  const content = Array.isArray(node.content)
    ? node.content.map((child, childIndex) => normalizeEditorNode(child, childIndex)).filter(Boolean)
    : []
  const safeNode = { type }
  if (Object.keys(attrs).length > 0) safeNode.attrs = attrs
  if (content.length > 0) safeNode.content = content
  if (typeof node.text === 'string' && node.text) safeNode.text = node.text
  if (typeof node.marks !== 'undefined' && Array.isArray(node.marks)) safeNode.marks = node.marks
  return safeNode
}

function buildTiptapDoc(blocks = []) {
  const content = blocks
    .filter((block) => block && typeof block === 'object' && typeof block.type === 'string')
    .map((block) => {
      if (block.type === 'heading') {
        return {
          type: 'heading',
          attrs: { level: block.level || 1, blockId: block.id, sourceNodeId: block.sourceNodeId },
          content: block.text ? [{ type: 'text', text: block.text }] : []
        }
      }
      if (block.type === 'table') {
        return {
          type: 'paragraph',
          attrs: { blockId: block.id, sourceNodeId: block.sourceNodeId, semanticType: block.semanticType, isReadOnly: true },
          content: [{ type: 'text', text: '[table]' }]
        }
      }
      if (block.type === 'image' || block.type === 'formula') {
        return {
          type: 'paragraph',
          attrs: { blockId: block.id, sourceNodeId: block.sourceNodeId, semanticType: block.semanticType, isReadOnly: true },
          content: [{ type: 'text', text: `[${block.semanticType}]` }]
        }
      }
      return {
        type: 'paragraph',
        attrs: { blockId: block.id, sourceNodeId: block.sourceNodeId, semanticType: block.semanticType },
        content: block.text ? [{ type: 'text', text: block.text }] : []
      }
    })
    .map((node, index) => normalizeEditorNode(node, index))
    .filter(Boolean)
  return { type: 'doc', content }
}

export async function fetchDocumentMeta() {
  await wait()
  const rawData = getRawData()
  const pages = Array.isArray(rawData?.pages) ? rawData.pages.map(normalizePage) : []
  const mergedNodes = Array.isArray(rawData?.merged_nodes) ? rawData.merged_nodes : []
  const blockModel = buildBlockModel(mergedNodes)
  const initialTiptapDoc = buildTiptapDoc(blockModel.blocks)
  return {
    code: 0,
    message: 'success',
    data: {
      document_meta: rawData?.document_meta || {},
      statistics: {
        page_count: pages.length,
        node_count: mergedNodes.length,
        heading_count: mergedNodes.filter((node) => node?.semantic_type === 'heading').length,
        image_count: mergedNodes.filter((node) => node?.semantic_type === 'image').length,
        table_count: mergedNodes.filter((node) => node?.semantic_type === 'table').length
      },
      pages,
      outline: buildOutlineNodes(mergedNodes),
      block_model: blockModel,
      initial_tiptap_doc: initialTiptapDoc
    }
  }
}

function buildBlocksFromTiptapDoc(doc = { type: 'doc', content: [] }) {
  const content = Array.isArray(doc?.content) ? doc.content : []
  return content
    .filter((node) => node && typeof node === 'object' && typeof node.type === 'string')
    .map((node, index) => {
      const semanticType = node?.attrs?.semanticType || node?.type || 'paragraph'
      const isReadOnly = Boolean(node?.attrs?.isReadOnly)
      const text = Array.isArray(node?.content)
        ? node.content
          .filter((child) => child && typeof child === 'object')
          .map((child) => child?.text || '')
          .join('')
        : ''
      return {
        id: node?.attrs?.blockId || `editor_block_${index}`,
        pageIdx: Number(node?.attrs?.pageIdx || 0),
        type: node?.type || 'paragraph',
        semanticType,
        text,
        level: Number(node?.attrs?.level || 0) || null,
        style: {},
        sourceNodeId: node?.attrs?.sourceNodeId || node?.attrs?.blockId || `editor_block_${index}`,
        translationNodeId: `${node?.attrs?.blockId || `editor_block_${index}`}__translation`,
        parentId: node?.attrs?.parentId || null,
        order: index,
        pageNodeOrder: index,
        isReadOnly,
        children: [],
        displayText: isReadOnly ? text.replace(/^\[(image|formula)\]$/i, '').trim() || text : text
      }
    })
}

export async function fetchDocumentPage(pageIdx) {
  await wait()
  const targetPageIdx = Number(pageIdx || 0)
  const rawData = getRawData()
  const pages = Array.isArray(rawData?.pages) ? rawData.pages : []
  const mergedNodes = Array.isArray(rawData?.merged_nodes) ? rawData.merged_nodes : []
  const page = pages.find((item) => Number(item?.page_idx) === targetPageIdx)
  const nodes = mergedNodes
    .filter((node) => Number(node?.page_idx) === targetPageIdx)
    .sort((left, right) => Number(left?.layout?.reading_order || 0) - Number(right?.layout?.reading_order || 0))
    .map(normalizeNode)

  return {
    code: 0,
    message: 'success',
    data: {
      page: normalizePage(page || { page_idx: targetPageIdx }),
      nodes,
      blocks: nodes.map((node) => node.block),
      page_map: {
        [targetPageIdx]: nodes.map((node) => node.block)
      },
      page_node_map: {
        [targetPageIdx]: nodes.map((node, index) => ({
          nodeId: node.node_id,
          blockId: node.block.id,
          type: node.block.type,
          semanticType: node.block.semanticType,
          order: Number(node.block.order ?? index)
        }))
      }
    }
  }
}

export function toBlockListFromEditorDoc(doc) {
  return buildBlocksFromTiptapDoc(doc)
}
