import {getData} from './parse_image'
import {imageSize} from '../image-size'
import util from './util'
import SparkMD5 from 'spark-md5'

export const getPhotoMetadata = async (file) => {
  let extent = getFileExtent(file)
  let data = {}
  if (extent === 'jpg' || extent === 'jpeg') {
    try {
      data = await _formatMetadata(file)
    } catch(err) {
      data = await getImageSize(file)
    }
  } else {
    data = await getImageSize(file)
  }
  data.filesize = getFileSize(file)
  return data
}

async function _formatMetadata (file, index = 1) {
  let buffer = await getFileBuffer(file, index)
  let md5 = getMd5(buffer)
  return new Promise((resolve, reject) => {
    getData(buffer, function (img, err) {
      if (err) {
        if (err.message === 'Offset is outside the bounds of the DataView' && index < 3) {// 如果前64kb没找到，则尝试搜索128k，最多搜索192k
          return resolve(_formatMetadata(file, index + 1))
        } else {
          return reject(err)
        }
      }
      let {exif, xmp} = getAllTags(img)
      exif = JSON.parse(JSON.stringify(exif).replaceAll('\\u0000', '')) || {}
      if (exif.PixelXDimension && exif.PixelYDimension && exif.PixelXDimension != 65535 && exif.PixelYDimension != 65535) {
        resolve({
          exif, xmp,
          width: exif.PixelXDimension,
          height: exif.PixelYDimension,
          md5
        })
      } else {
        getImageSize(file).then(size => {
          resolve({
            exif, xmp,
            width: size.width,
            height: size.height,
            md5
          })
        })
      }
    })
  })
}

async function getImageSize (file) {
  try {
    let buffer = await getFileBuffer(file)
    let size = imageSize(buffer)
    let md5 = getMd5(buffer)
    return {
      width: size.width,
      height: size.height,
      md5
    }
  } catch (err) {
    return {
      width: 0,
      height: 0
    }
  }  
}

function getAllTags (img) {
  if (!util.imageHasData(img)) return {
    exif: {},
    xmp: {}
  }
  return {
    exif: img.exifdata || {},
    xmp: img.xmpdata || {}
  }
}

function getFileExtent (file) {
  if (typeof file === 'string') {
    return file.split('.').pop().toLowerCase()
  } else {
    return file.name.split('.').pop().toLowerCase()
  }
}

async function getFileBuffer (file, index) {
  if ((typeof file) === 'string') {
    const fs = require('fs')
    if (!index) {
      let buffer = fs.readFileSync(file)
      return buffer.buffer
    } else {
      let fd = fs.openSync(file)
      let buffer = Buffer.alloc(65536 * index)
      await new Promise((resolve) => {
        fs.read(fd, buffer, 0, buffer.length, 0, () => {
          resolve()
          fs.closeSync(fd)
        })
      })
      return buffer.buffer
    }
  } else {
    if (index) {
      file = file.slice(0, 65536 * index)
    }
    return await new Promise((resolve, reject) => {
      var fileReader = new FileReader()
      fileReader.readAsArrayBuffer(file)
      fileReader.onload = (e) => {
        resolve(e.target.result)
      }
      fileReader.onerror = (error) => {
        reject(error)
      }
    })
    
  }
}

function getFileSize(file) {
  if (typeof file === 'string') {
    let stat = fs.statSync(file)
    data.filesize = stat.size
  } else {
    return file.size
  }
}

function getMd5 (buffer) {
  let spark = new SparkMD5.ArrayBuffer()
  spark.append(buffer)
  let md5 = spark.end()
  return md5
}