import {
  ExtractCrumbResponseSchema,
  type ExtractCrumbDraft,
} from '@crumbs/core/schemas'

import {toApiError} from '@/lib/errors'
import {downscaleJpeg} from '@/lib/image'
import {getLlmKey} from '@/lib/llm-key'
import {rpc} from '@/lib/rpc'

const MAX_EDGE = 1568

export class MissingLlmKeyError extends Error {}

type ImageInput = {uri: string; width?: number; height?: number}

const MIME_TYPE = 'image/jpeg'

const downscale = async (image: ImageInput): Promise<string> => {
  const result = await downscaleJpeg(image, {
    maxEdge: MAX_EDGE,
    base64: true,
  })
  if (!result.base64) throw new Error('failed to encode image')
  return result.base64
}

const parseDrafts = async (res: {
  ok: boolean
  status: number
  text: () => Promise<string>
  json: () => Promise<unknown>
}): Promise<ExtractCrumbDraft[]> => {
  if (!res.ok) throw await toApiError(res)
  const {drafts} = ExtractCrumbResponseSchema.parse(await res.json())
  return drafts
}

export const extractCrumbFromImage = async (
  image: ImageInput,
): Promise<ExtractCrumbDraft[]> => {
  const apiKey = await getLlmKey()
  if (!apiKey) throw new MissingLlmKeyError()

  const base64 = await downscale(image)

  const res = await rpc.extract.$post(
    {json: {image: base64, mimeType: MIME_TYPE}},
    {headers: {'X-LLM-Key': apiKey}},
  )
  return parseDrafts(res)
}

// links parse server-side without an llm key
export const extractCrumbsFromUrl = async (
  url: string,
): Promise<ExtractCrumbDraft[]> => {
  const res = await rpc.extract.$post({json: {url}})
  return parseDrafts(res)
}
