import { mkdir, readFile, writeFile } from 'fs/promises'
import { dirname, extname, join } from 'path'

import { app } from 'electron'

const IMAGE_FOLDER_NAME = 'images'

type ImageScope = 'classes' | 'students'

const MIME_EXTENSION_MAP: Record<string, string> = {
  'image/jpeg': 'jpg',
  'image/jpg': 'jpg',
  'image/png': 'png',
  'image/webp': 'webp',
  'image/bmp': 'bmp',
  'image/gif': 'gif'
}

const EXTENSION_MIME_MAP: Record<string, string> = {
  jpg: 'image/jpeg',
  jpeg: 'image/jpeg',
  png: 'image/png',
  webp: 'image/webp',
  bmp: 'image/bmp',
  gif: 'image/gif'
}

function parseDataUrl(value: string): { mimeType: string; extension: string; buffer: Buffer } | null {
  const match = value.match(/^data:(image\/[^;]+);base64,(.+)$/)

  if (!match) {
    return null
  }

  const mimeType = match[1].toLowerCase()
  const extension = MIME_EXTENSION_MAP[mimeType] ?? 'jpg'

  return {
    mimeType,
    extension,
    buffer: Buffer.from(match[2], 'base64')
  }
}

function sanitizePathPart(value: string): string {
  return (
    [...value]
      .filter((character) => !'<>:"/\\|?*'.includes(character) && character.charCodeAt(0) >= 32)
      .join('')
      .trim() || 'unknown'
  )
}

function getRelativeImagePath(
  scope: ImageScope,
  ownerId: string,
  fieldName: string,
  extension: string
): string {
  return [
    IMAGE_FOLDER_NAME,
    scope,
    sanitizePathPart(ownerId),
    `${sanitizePathPart(fieldName)}.${extension}`
  ].join('/')
}

function resolveImagePath(value: string): string {
  return join(app.getPath('userData'), ...value.split('/').filter(Boolean))
}

function getMimeTypeFromPath(value: string): string {
  const extension = extname(value).replace(/^\./, '').toLowerCase()
  return EXTENSION_MIME_MAP[extension] ?? 'image/jpeg'
}

export function isDataUrlImage(value?: string | null): boolean {
  return Boolean(value?.startsWith('data:image/'))
}

export async function storeImageValue(
  scope: ImageScope,
  ownerId: string,
  fieldName: string,
  value?: string | null
): Promise<string> {
  if (!value) {
    return ''
  }

  const parsed = parseDataUrl(value)

  if (!parsed) {
    return value
  }

  const relativePath = getRelativeImagePath(scope, ownerId, fieldName, parsed.extension)
  const absolutePath = resolveImagePath(relativePath)

  await mkdir(dirname(absolutePath), { recursive: true })
  await writeFile(absolutePath, parsed.buffer)

  return relativePath
}

export async function readImageAsDataUrl(value?: string | null): Promise<string> {
  if (!value) {
    return ''
  }

  if (isDataUrlImage(value)) {
    return value
  }

  const buffer = await readFile(resolveImagePath(value))
  return `data:${getMimeTypeFromPath(value)};base64,${buffer.toString('base64')}`
}

export async function readImageBuffer(value?: string | null): Promise<Buffer | null> {
  if (!value) {
    return null
  }

  const parsed = parseDataUrl(value)

  if (parsed) {
    return parsed.buffer
  }

  return readFile(resolveImagePath(value))
}
