import type { Stroke, RecognitionCandidate } from './types'
import { strokesToCanvas } from './preprocess'
import type Tesseract from 'tesseract.js'
import type { PSM } from 'tesseract.js'

let worker: Tesseract.Worker | null = null
let loading = false

export function isReady(): boolean {
  return worker !== null
}

export async function init(): Promise<void> {
  if (worker || loading) return
  loading = true

  try {
    const Tesseract = await import('tesseract.js')
    worker = await Tesseract.createWorker('eng')
    await worker.setParameters({
      tessedit_char_whitelist: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
      // SAFETY: '10' is exactly PSM.SINGLE_CHAR, so the literal lands inside the enum's value set
      tessedit_pageseg_mode: '10' as PSM, // single character
    })
  } catch (e) {
    console.warn('Tesseract init failed:', e)
    worker = null
  }
  loading = false
}

export async function recognize(strokes: Stroke[]): Promise<RecognitionCandidate[]> {
  if (!worker) return []

  try {
    const imageData = strokesToCanvas(strokes, 128)

    // convert ImageData to canvas for tesseract
    const canvas = new OffscreenCanvas(128, 128)
    const ctx = canvas.getContext('2d')!
    ctx.putImageData(imageData, 0, 0)
    const blob = await canvas.convertToBlob({ type: 'image/png' })

    const result = await worker.recognize(blob)
    const text = result.data.text.trim().toUpperCase()

    if (text.length === 1 && text >= 'A' && text <= 'Z') {
      const confidence = result.data.confidence / 100
      return [{ letter: text, confidence }]
    }

    return []
  } catch (e) {
    console.warn('Tesseract recognition failed:', e)
    return []
  }
}
