import { renderLegacyAttachmentAssociationHtml } from './aiConversationLegacyAttachmentRenderer.js'
import { parseTableRow, renderTable } from './aiConversationTableRenderer.js'
import {
  DOCUMENT_DETAIL_HREF_PREFIX,
  extractTrustedHtmlBlocks,
  normalizeConversationText,
  restoreTrustedHtmlBlocks
} from './conversationTrustedHtml.js'

const APPLICATION_DETAIL_HREF_PREFIX = '#ai-open-application-detail:'
const DELETED_APPLICATION_DETAIL_HREF_PREFIX = '#ai-deleted-application-detail:'
const DELETED_DOCUMENT_DETAIL_HREF_PREFIX = '#ai-deleted-document-detail:'

function escapeHtml(value = '') {
  return String(value)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

function sanitizeHref(href = '') {
  const value = String(href || '').trim()
  if (/^(https?:\/\/|#)/i.test(value)) {
    return escapeHtml(value)
  }
  return '#'
}

function isApplicationDetailHref(href = '') {
  return String(href || '').trim().startsWith(APPLICATION_DETAIL_HREF_PREFIX)
}

function isDeletedApplicationDetailHref(href = '') {
  return String(href || '').trim().startsWith(DELETED_APPLICATION_DETAIL_HREF_PREFIX)
}

function isDocumentDetailHref(href = '') {
  return String(href || '').trim().startsWith(DOCUMENT_DETAIL_HREF_PREFIX)
}

function isDeletedDocumentDetailHref(href = '') {
  return String(href || '').trim().startsWith(DELETED_DOCUMENT_DETAIL_HREF_PREFIX)
}

function sanitizeImageSrc(src = '') {
  const value = String(src || '').trim()
  if (/^(https?:\/\/|blob:|\/)/i.test(value)) {
    return escapeHtml(value)
  }
  if (/^data:image\/(?:png|jpe?g|webp|gif);base64,[a-z0-9+/=]+$/i.test(value)) {
    return escapeHtml(value)
  }
  return ''
}

function renderLinkHtml(label = '', href = '') {
  const sanitizedHref = sanitizeHref(href)
  if (isDeletedApplicationDetailHref(href)) {
    return [
      '<span',
      ' class="ai-html-action-link ai-html-action-link-application is-disabled"',
      ' data-ai-action="deleted-application-detail"',
      ' aria-disabled="true"',
      '>',
      label,
      '</span>'
    ].join('')
  }
  if (isDeletedDocumentDetailHref(href)) {
    return [
      '<span',
      ' class="ai-html-action-link ai-html-action-link-document is-disabled"',
      ' data-ai-action="deleted-document-detail"',
      ' aria-disabled="true"',
      '>',
      label,
      '</span>'
    ].join('')
  }
  if (isApplicationDetailHref(href)) {
    return [
      `<a href="${sanitizedHref}"`,
      ' class="ai-html-action-link ai-html-action-link-application"',
      ' data-ai-action="open-application-detail"',
      '>',
      label,
      '</a>'
    ].join('')
  }
  if (isDocumentDetailHref(href)) {
    return [
      `<a href="${sanitizedHref}"`,
      ' class="ai-html-action-link ai-html-action-link-document"',
      ' data-ai-action="open-document-detail"',
      '>',
      label,
      '</a>'
    ].join('')
  }
  return `<a href="${sanitizedHref}" target="_blank" rel="noreferrer">${label}</a>`
}

function renderInlineImageHtml(alt = '', src = '') {
  const sanitizedSrc = sanitizeImageSrc(src)
  if (!sanitizedSrc) {
    return escapeHtml(alt || src)
  }
  return [
    `<img class="ai-html-inline-image" src="${sanitizedSrc}"`,
    ` alt="${escapeHtml(alt)}" loading="lazy" />`
  ].join('')
}

function renderInlineHtml(value = '') {
  let html = escapeHtml(value)
  html = html.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g, (_match, alt, src) => (
    renderInlineImageHtml(alt, src)
  ))
  html = html.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+|#[^\s)]+)\)/g, (_match, label, href) => (
    renderLinkHtml(label, href)
  ))
  html = html.replace(/`([^`]+)`/g, '<code>$1</code>')
  html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
  html = html.replace(/__([^_]+)__/g, '<strong>$1</strong>')
  return html
}

function isFenceLine(line = '') {
  return /^\s*(```|~~~)/.test(String(line || ''))
}

function isHeadingLine(line = '') {
  return /^#{1,6}\s+/.test(String(line || '').trim())
}

function isQuoteLine(line = '') {
  return /^>\s?/.test(String(line || '').trim())
}

function isUnorderedListLine(line = '') {
  return /^[-*+]\s+/.test(String(line || '').trim())
}

function isOrderedListLine(line = '') {
  return /^\d+\.\s+/.test(String(line || '').trim())
}

function isHorizontalRuleLine(line = '') {
  return /^(-{3,}|\*{3,}|_{3,})$/.test(String(line || '').trim())
}

function isTableDivider(line = '') {
  const cells = parseTableRow(line)
  return cells.length > 1 && cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()))
}

function isTableStart(lines, index) {
  const current = String(lines[index] || '').trim()
  const next = String(lines[index + 1] || '').trim()
  return current.startsWith('|') && next.startsWith('|') && isTableDivider(next)
}

function parseImageLine(line = '') {
  const match = String(line || '').trim().match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/)
  if (!match) {
    return null
  }
  const src = sanitizeImageSrc(match[2])
  if (!src) {
    return null
  }
  return {
    alt: String(match[1] || '').trim(),
    src
  }
}

function splitLabelAndBody(rawText = '') {
  const text = String(rawText || '').trim()
  const strongMatch = text.match(/^\*\*([^*]+)\*\*[：:]\s*(.*)$/u)
  if (strongMatch) {
    return {
      label: strongMatch[1].trim(),
      body: strongMatch[2].trim()
    }
  }

  const plainText = text.replace(/\*\*/g, '')
  const match = plainText.match(/^([^：:\n]{2,20})[：:]\s*(.*)$/u)
  if (!match) {
    return null
  }
  return {
    label: match[1].trim(),
    body: match[2].trim()
  }
}

function isSpecialBlockStart(lines, index) {
  const line = String(lines[index] || '').trim()
  return (
    !line ||
    isFenceLine(line) ||
    isHeadingLine(line) ||
    isQuoteLine(line) ||
    isUnorderedListLine(line) ||
    isOrderedListLine(line) ||
    isHorizontalRuleLine(line) ||
    Boolean(parseImageLine(line)) ||
    isTableStart(lines, index)
  )
}

function nextNonEmptyLineMatches(lines, index, predicate) {
  let cursor = index + 1
  while (cursor < lines.length) {
    const nextLine = String(lines[cursor] || '').trim()
    if (nextLine) {
      return predicate(nextLine)
    }
    cursor += 1
  }
  return false
}

function renderHeading(line = '') {
  const match = String(line || '').trim().match(/^(#{1,6})\s+(.+)$/)
  if (!match) {
    return ''
  }
  const level = Math.min(Math.max(match[1].length, 2), 4)
  const className = level === 3 ? 'ai-html-title' : `ai-html-title ai-html-title--level-${level}`
  return `<h${level} class="${className}">${renderInlineHtml(match[2])}</h${level}>`
}

function renderParagraph(lines = []) {
  const text = lines.map((line) => String(line || '').trim()).filter(Boolean).join(' ')
  return text ? `<p class="ai-html-paragraph">${renderInlineHtml(text)}</p>` : ''
}

function renderImageBlock(line = '') {
  const image = parseImageLine(line)
  if (!image) {
    return ''
  }
  return [
    '<figure class="ai-html-image-frame">',
    `<img class="ai-html-image" src="${image.src}" alt="${escapeHtml(image.alt)}" loading="lazy" />`,
    image.alt ? `<figcaption class="ai-html-image-caption">${escapeHtml(image.alt)}</figcaption>` : '',
    '</figure>'
  ].join('')
}

function renderQuoteBlock(items = []) {
  const normalizedItems = items
    .map((item) => String(item || '').replace(/^>\s?/, '').trim())
    .filter(Boolean)
  if (!normalizedItems.length) {
    return ''
  }

  const focusItems = normalizedItems
    .map((item) => splitLabelAndBody(item))
    .filter(Boolean)
  if (focusItems.length === normalizedItems.length) {
    return [
      '<section class="ai-html-focus-grid" aria-label="重点信息">',
      ...focusItems.map((item) => [
        '<article class="ai-html-focus-card">',
        `<span class="ai-html-focus-label">${renderInlineHtml(item.label)}</span>`,
        `<p>${renderInlineHtml(item.body)}</p>`,
        '</article>'
      ].join('')),
      '</section>'
    ].join('')
  }

  return [
    '<aside class="ai-html-callout">',
    ...normalizedItems.map((item) => `<p>${renderInlineHtml(item)}</p>`),
    '</aside>'
  ].join('')
}

function renderUnorderedList(items = []) {
  const parsedItems = items
    .map((item) => String(item || '').trim().replace(/^[-*+]\s+/, '').trim())
    .filter(Boolean)
  const structuredItems = parsedItems
    .map((item) => splitLabelAndBody(item))
    .filter(Boolean)

  if (structuredItems.length === parsedItems.length && parsedItems.length > 0) {
    return [
      '<ul class="ai-html-steps">',
      ...structuredItems.map((item, index) => [
        '<li>',
        `<span class="ai-html-step-index">${index + 1}</span>`,
        '<div class="ai-html-step-copy">',
        `<strong>${renderInlineHtml(item.label)}</strong>`,
        item.body ? `<p>${renderInlineHtml(item.body)}</p>` : '',
        '</div>',
        '</li>'
      ].join('')),
      '</ul>'
    ].join('')
  }

  return [
    '<ul class="ai-html-list">',
    ...parsedItems.map((item) => `<li>${renderInlineHtml(item)}</li>`),
    '</ul>'
  ].join('')
}

function renderOrderedList(items = []) {
  const parsedItems = items
    .map((item) => String(item || '').trim().replace(/^\d+\.\s+/, '').trim())
    .filter(Boolean)
  return [
    '<ol class="ai-html-list ai-html-list--ordered">',
    ...parsedItems.map((item) => `<li>${renderInlineHtml(item)}</li>`),
    '</ol>'
  ].join('')
}

function renderCodeBlock(lines = []) {
  const code = lines.join('\n').replace(/\n$/, '')
  return `<pre class="ai-html-code"><code>${escapeHtml(code)}</code></pre>`
}

export function renderAiConversationHtml(content = '') {
  const legacyAttachmentAssociationHtml = renderLegacyAttachmentAssociationHtml(content, { escapeHtml })
  if (legacyAttachmentAssociationHtml) {
    return legacyAttachmentAssociationHtml
  }

  const extracted = extractTrustedHtmlBlocks(content)
  const normalized = normalizeConversationText(extracted.content, { trim: true })
  if (!normalized) {
    return ''
  }

  const lines = normalized.split('\n')
  const blocks = []
  let index = 0

  while (index < lines.length) {
    const line = String(lines[index] || '')
    const trimmed = line.trim()

    if (!trimmed) {
      index += 1
      continue
    }

    if (isFenceLine(trimmed)) {
      index += 1
      const codeLines = []
      while (index < lines.length && !isFenceLine(lines[index])) {
        codeLines.push(lines[index])
        index += 1
      }
      if (index < lines.length) {
        index += 1
      }
      blocks.push(renderCodeBlock(codeLines))
      continue
    }

    if (isHeadingLine(trimmed)) {
      blocks.push(renderHeading(trimmed))
      index += 1
      continue
    }

    if (isTableStart(lines, index)) {
      const tableLines = []
      while (index < lines.length && String(lines[index] || '').trim().startsWith('|')) {
        tableLines.push(lines[index])
        index += 1
      }
      blocks.push(renderTable(tableLines, { escapeHtml, renderInlineHtml }))
      continue
    }

    if (parseImageLine(trimmed)) {
      blocks.push(renderImageBlock(trimmed))
      index += 1
      continue
    }

    if (isQuoteLine(trimmed)) {
      const quoteItems = []
      while (index < lines.length) {
        const current = String(lines[index] || '').trim()
        if (isQuoteLine(current)) {
          quoteItems.push(current)
          index += 1
          continue
        }
        if (!current && isQuoteLine(String(lines[index + 1] || '').trim())) {
          index += 1
          continue
        }
        break
      }
      blocks.push(renderQuoteBlock(quoteItems))
      continue
    }

    if (isUnorderedListLine(trimmed)) {
      const listItems = []
      while (index < lines.length) {
        const current = String(lines[index] || '').trim()
        if (isUnorderedListLine(current)) {
          listItems.push(lines[index])
          index += 1
          continue
        }
        if (!current && nextNonEmptyLineMatches(lines, index, isUnorderedListLine)) {
          index += 1
          continue
        }
        break
      }
      blocks.push(renderUnorderedList(listItems))
      continue
    }

    if (isOrderedListLine(trimmed)) {
      const listItems = []
      while (index < lines.length) {
        const current = String(lines[index] || '').trim()
        if (isOrderedListLine(current)) {
          listItems.push(lines[index])
          index += 1
          continue
        }
        if (!current && nextNonEmptyLineMatches(lines, index, isOrderedListLine)) {
          index += 1
          continue
        }
        break
      }
      blocks.push(renderOrderedList(listItems))
      continue
    }

    if (isHorizontalRuleLine(trimmed)) {
      blocks.push('<hr class="ai-html-divider" />')
      index += 1
      continue
    }

    const paragraphLines = []
    while (index < lines.length && !isSpecialBlockStart(lines, index)) {
      paragraphLines.push(lines[index])
      index += 1
    }
    blocks.push(renderParagraph(paragraphLines))
  }

  return restoreTrustedHtmlBlocks(
    `<div class="ai-html-flow">${blocks.filter(Boolean).join('')}</div>`,
    extracted.trustedHtmlBlocks,
    { paragraphClass: 'ai-html-paragraph' }
  )
}
