import type { TipTapJSON } from "@/lib/drive/richtext-import"

const BASE64_PREFIX = "data:"

/** Collect base64 image src values from TipTap JSON. */
export function collectBase64ImageSrcs(content: TipTapJSON): string[] {
  const srcs: string[] = []
  const walk = (node: unknown) => {
    if (!node || typeof node !== "object") return
    const record = node as TipTapJSON
    const attrs = record.attrs as Record<string, unknown> | undefined
    if (
      (record.type === "image" ||
        record.type === "docsGraphic" ||
        record.type === "docsInlineGraphic") &&
      typeof attrs?.src === "string" &&
      attrs.src.startsWith(BASE64_PREFIX)
    ) {
      srcs.push(attrs.src)
    }
    if (Array.isArray(record.content)) record.content.forEach(walk)
  }
  walk(content)
  return srcs
}

export type UploadedAsset = {
  assetId: string
  url: string
}

/** Upload a base64 image and return asset reference. Phase 2 blob migration. */
export async function uploadGraphicAsset(
  src: string,
  uploadFn: (body: { dataUrl: string }) => Promise<UploadedAsset>
): Promise<UploadedAsset | null> {
  if (!src.startsWith(BASE64_PREFIX)) return null
  try {
    return await uploadFn({ dataUrl: src })
  } catch {
    return null
  }
}

/** Replace base64 src with asset URL in TipTap JSON (lazy migration). */
export function applyAssetToContent(
  content: TipTapJSON,
  src: string,
  asset: UploadedAsset
): TipTapJSON {
  const walk = (node: unknown): unknown => {
    if (!node || typeof node !== "object") return node
    if (Array.isArray(node)) return node.map(walk)
    const record = node as TipTapJSON
    const attrs = record.attrs as Record<string, unknown> | undefined
    if (
      attrs &&
      attrs.src === src &&
      (record.type === "image" ||
        record.type === "docsGraphic" ||
        record.type === "docsInlineGraphic")
    ) {
      return {
        ...record,
        attrs: { ...attrs, src: asset.url, assetId: asset.assetId },
      }
    }
    if (Array.isArray(record.content)) {
      return { ...record, content: record.content.map(walk) }
    }
    return record
  }
  const next = walk(content)
  return (next && typeof next === "object" ? next : content) as TipTapJSON
}

/** Migrate all base64 images in document to backend assets when uploadFn provided. */
export async function migrateBase64ImagesInContent(
  content: TipTapJSON,
  uploadFn: (body: { dataUrl: string }) => Promise<UploadedAsset>
): Promise<TipTapJSON> {
  let result = content
  const srcs = [...new Set(collectBase64ImageSrcs(content))]
  for (const src of srcs) {
    const asset = await uploadGraphicAsset(src, uploadFn)
    if (asset) result = applyAssetToContent(result, src, asset)
  }
  return result
}
