const SIZE_LIMIT = 32 * 1024
export const IMAGE_SIZE_LIMIT = 100 * 1024 * 1024

// ─── Status enum ───────────────────────────────────────────────
export const OcrStatus = Object.freeze({
  PENDING: 'pending',
  LOADING: 'loading',
  SUCCESS: 'success',
  FAILED: 'failed',
})

// ─── State cache (per-image-hash) ──────────────────────────────
// Map<hash, { status, text?, error?, updatedAt }>
const ocrStateCache = new Map()

// ─── Legacy text cache (kept for backward compat) ──────────────
const ocrCache = new Map()
const imageHashCache = new Map()

// ─── Hash utilities ────────────────────────────────────────────
export async function calculateImageHash(imageBytes) {
  const hashBuffer = await crypto.subtle.digest('SHA-256', imageBytes)
  const hashArray = Array.from(new Uint8Array(hashBuffer))
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
}

// ─── State API (new) ───────────────────────────────────────────
export function setOcrState(hash, status, text = '', error = '') {
  ocrStateCache.set(hash, {
    status,
    text: typeof text === 'string' ? text : '',
    error: typeof error === 'string' ? error : '',
    updatedAt: Date.now(),
  })
}

export function getOcrState(hash) {
  return ocrStateCache.get(hash) || { status: OcrStatus.PENDING, text: '', error: '' }
}

export function resetOcrState(hash) {
  ocrStateCache.delete(hash)
}

export function clearAllOcrState() {
  ocrStateCache.clear()
}

// ─── Legacy API (backward compat) ──────────────────────────────
export function getOcrByHash(hash) {
  const state = ocrStateCache.get(hash)
  if (state && state.status === OcrStatus.SUCCESS) return state.text
  return imageHashCache.get(hash) || ''
}

export function setOcrByHash(hash, text) {
  imageHashCache.set(hash, text)
}

export function setOcrCache(filename, text) {
  ocrCache.set(filename, text)
}

export function getOcrCache(filename) {
  return ocrCache.get(filename) || ''
}

export function clearOcrCache(filename) {
  ocrCache.delete(filename)
}

export function hasOcrCache(filename) {
  return ocrCache.has(filename)
}

export function clearAllOcrCache() {
  ocrCache.clear()
}

// ─── Size utilities ────────────────────────────────────────────
export function calculateOcrSize(imageFilenames) {
  let total = 0
  for (const name of imageFilenames) {
    const text = ocrCache.get(name)
    if (text) total += new Blob([text]).size
  }
  return total
}

export function checkSizeLimit(docTextSize, imageFilenames) {
  const ocrSize = calculateOcrSize(imageFilenames)
  const total = docTextSize + ocrSize
  return {
    size: total,
    docSize: docTextSize,
    ocrSize: ocrSize,
    overLimit: total > SIZE_LIMIT,
  }
}

export const OCR_SIZE_LIMIT = SIZE_LIMIT

// ─── Text extraction ───────────────────────────────────────────
export function extractTextFromOCR(ocrText, maxLen = 100) {
  if (!ocrText) return ''
  const match = ocrText.match(/TEXT:\s*([\s\S]*?)(?:KEY_DETAILS|LANGUAGE|SUMMARY|$)/i)
  let text = match ? match[1].trim() : ocrText.trim()
  if (text.toLowerCase() === '(none)') return ''
  return text.length > maxLen ? text.substring(0, maxLen) + '...' : text
}

// ─── Context builder (for AI completion) ───────────────────────
const IMAGE_NODE_TYPES = new Set(['image', 'image-block', 'imageBlock'])

export function buildOcrContextForDoc(doc, maxLen = 120) {
  const lines = []

  doc.descendants((node) => {
    if (!IMAGE_NODE_TYPES.has(node.type.name)) return true
    const src = typeof node.attrs?.src === 'string' ? node.attrs.src : ''
    if (!src) return true

    const ocrText = getOcrCache(src)
    const preview = ocrText ? extractTextFromOCR(ocrText, maxLen) : ''
    if (!preview) return true

    const label = typeof node.attrs?.alt === 'string' && node.attrs.alt.trim()
      ? node.attrs.alt.trim()
      : 'image'
    lines.push(`![${label}](${src}) <OCR:${preview}>`)
    return true
  })

  return lines.join('\n')
}
