const fs = require('fs/promises')
const path = require('path')
const crypto = require('crypto')
const sharp = require('sharp')
const { nanoid } = require('nanoid')
const {
  ensureData,
  closePool,
  listReferencedUploadSources,
  findImageAssetBySrc,
  createImageAsset,
} = require('../src/db')

const BACKEND_ROOT = path.join(__dirname, '..')

function inferMimeType(src, metadata) {
  const format = String(metadata?.format || '').toLowerCase()
  if (format === 'jpeg' || format === 'jpg') return 'image/jpeg'
  if (format === 'png') return 'image/png'
  if (format === 'gif') return 'image/gif'
  if (format === 'webp') return 'image/webp'
  if (format === 'svg' || format === 'svg+xml') return 'image/svg+xml'
  if (format === 'avif') return 'image/avif'

  const ext = path.extname(src || '').toLowerCase()
  if (ext === '.jpg' || ext === '.jpeg') return 'image/jpeg'
  if (ext === '.png') return 'image/png'
  if (ext === '.gif') return 'image/gif'
  if (ext === '.webp') return 'image/webp'
  if (ext === '.svg') return 'image/svg+xml'
  if (ext === '.avif') return 'image/avif'
  return 'application/octet-stream'
}

async function main() {
  await ensureData()

  const referencedSrcs = Array.from(new Set(await listReferencedUploadSources()))
    .filter((src) => typeof src === 'string' && src.startsWith('/uploads/'))
    .sort()

  const summary = {
    scanned: referencedSrcs.length,
    skippedExisting: 0,
    backfilled: 0,
    missingFiles: 0,
    failed: 0,
  }

  for (const src of referencedSrcs) {
    const existing = await findImageAssetBySrc(src)
    if (existing) {
      summary.skippedExisting += 1
      continue
    }

    const absolutePath = path.join(BACKEND_ROOT, src.replace(/^\//, ''))

    try {
      const [buffer, stat] = await Promise.all([fs.readFile(absolutePath), fs.stat(absolutePath)])
      let metadata = {}
      try {
        metadata = await sharp(buffer, { failOn: 'none' }).metadata()
      } catch (error) {
        metadata = {}
      }

      const rawHash = crypto.createHash('sha256').update(buffer).digest('hex')
      const contentHash = crypto.createHash('sha256').update(`${rawHash}|${src}`).digest('hex')

      await createImageAsset({
        id: nanoid(),
        contentHash,
        src,
        mimeType: inferMimeType(src, metadata),
        byteSize: Number(stat.size || 0),
        originalByteSize: Number(stat.size || 0),
        width: Number(metadata.width || 0),
        height: Number(metadata.height || 0),
      })
      summary.backfilled += 1
    } catch (error) {
      if (error?.code === 'ENOENT') {
        summary.missingFiles += 1
        continue
      }
      if (error?.code === 'ER_DUP_ENTRY') {
        summary.skippedExisting += 1
        continue
      }
      summary.failed += 1
      console.error('[backfill-legacy-image-assets] failed:', src, error?.message || error)
    }
  }

  console.log(JSON.stringify(summary, null, 2))
}

main()
  .catch((error) => {
    console.error(error)
    process.exitCode = 1
  })
  .finally(async () => {
    await closePool()
  })
