import {getPhotoMetadata} from './exif'
import moment from 'moment'
import * as util from '../util'
import _ from 'lodash'

export async function parsePhoto (file) {
  let tags = await getPhotoMetadata(file)
  const {width, height, exif, xmp, filesize, md5} = tags
  let imageMetaData = {width, height, filesize, md5}
  let lng = NaN, lat = NaN, alt = NaN
  let yaw = NaN, pitch = NaN, roll = NaN
  let x_std = NaN, y_std = NaN, z_std = NaN
  let pos = [lng, lat, alt]
  let flatedXmp = util.flatObject(xmp)
  let {GPSAltitude, GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef} = exif || {}
  if (GPSLongitude && GPSLatitude) {
    pos = [
      util.getGeoCoordOperator(GPSLongitudeRef) * util.toRadian(GPSLongitude),
      util.getGeoCoordOperator(GPSLatitudeRef) * util.toRadian(GPSLatitude),
      +GPSAltitude
    ]
  }
  for(let key in flatedXmp) {
    let value = flatedXmp[key]
    if (key === 'drone-dji:GpsLongtitude' || key === 'drone-dji:GpsLongitude') {
      lng = Number(value)
    } else if (key === 'drone-dji:GpsLatitude') {
      lat = Number(value)
    } else if (key === 'drone-dji:AbsoluteAltitude') {
      alt = Number(value)
    } else if (key === 'drone-dji:GimbalYawDegree') {
      yaw = Number(value)
    } else if (key === 'drone-dji:GimbalPitchDegree') {
      pitch = Number(value)
    } else if (key === 'drone-dji:GimbalRollDegree') {
      roll = Number(value)
    } else if (key === 'drone-dji:RtkStdLon') {
      x_std = Number(value)
    } else if (key === 'drone-dji:RtkStdLat') {
      y_std = Number(value)
    } else if (key === 'drone-dji:RtkStdHgt') {
      z_std = Number(value)
    } else if (key === 'drone-dji:DewarpFlag') {
      imageMetaData.dewarp_flag = Boolean(Number(value))
    } else if (key === 'drone-dji:RtkFlag') {
      imageMetaData.rtk_flag = Number(value)
    } else if (key === 'drone-dji:RelativeAltitude') {
      imageMetaData.relative_altitude = Number(value)
    } else if (key === 'tiff:Model') {
      imageMetaData.camera_model = value
    } else if (key === 'drone-dji:DewarpData') {
      let params = value.split(';')[1].split(',')
      let pre_calib_param = params.map(d => Number(d))
      pre_calib_param[2] = width / 2 + pre_calib_param[2]
      pre_calib_param[3] = height / 2 + pre_calib_param[3]
      imageMetaData.pre_calib_param = pre_calib_param
    } else if (key === 'drone-dji:CaptureUUID') {
      imageMetaData.capture_uuid = value
    } else if (key === 'drone-dji:DroneID') {
      imageMetaData.drone_id = value
    }
  }
  for(let key in flatedXmp) {
    let value = flatedXmp[key]
    if (key === 'drone-dji:GpsStatus' && value === 'RTK' && Number.isNaN(x_std)) {
      x_std = 0.02
      y_std = 0.02
    } else if (key === 'drone-dji:AltitudeType' && value === 'RtkAlt' && Number.isNaN(z_std)) {
      z_std = 0.02
    }
  }
  if (!Number.isNaN(x_std) && !Number.isNaN(y_std) && !Number.isNaN(z_std)) {
    imageMetaData.pos_std = [x_std, y_std, z_std]
  }
  if (!Number.isNaN(yaw) && !Number.isNaN(pitch) && !Number.isNaN(roll)) {
    imageMetaData.pitch_roll_yaw = [pitch, roll, yaw]
    imageMetaData.orientation = util.getRotationMatrix(pitch, roll, yaw)
  }
  if (exif?.DateTime) {
    imageMetaData.capture_time = moment(exif.DateTime, 'YYYY:MM:DD HH:mm:ss').valueOf()
  } else if (exif?.DateTimeOriginal) {
    imageMetaData.capture_time = moment(exif.DateTimeOriginal, 'YYYY:MM:DD HH:mm:ss').valueOf()
  }
  if (exif?.FocalLengthIn35mmFilm) {
    imageMetaData.focal_length_in_35mm = exif.FocalLengthIn35mmFilm
  }
  if (util.hasNaN(pos)) {
    pos = [lng, lat, alt]
  }
  if (!util.hasNaN(pos)) {
    imageMetaData.pos = pos
    imageMetaData.absolute_altitude = pos[2]
    imageMetaData.coordinate_system = {
      type: 2,
      label: 'WGS 84',
      type_name: 'Geographic',
      epsg_code: 4326
    }
    if (!util.hasNaN([x_std, y_std, z_std])) { // 估算pos_sigma
      let pos_sigma = []
      let accuracy = Math.sqrt(Math.pow(x_std, 2) + Math.pow(y_std, 2))
      if (accuracy < 0.03) {
        pos_sigma[0] = pos_sigma[1] = 0.03
      } else if (accuracy < 0.2) {
        pos_sigma[0] = pos_sigma[1] = 0.2
      } else {
        pos_sigma[0] = pos_sigma[1] = 2.0
      }

      if (z_std < 0.03) {
        pos_sigma[2] = 0.06
      } else if (z_std < 0.2) {
        pos_sigma[2] = 0.5
      } else {
        pos_sigma[2] = 5.0
      }
      imageMetaData.pos_sigma = pos_sigma
    } else {
      imageMetaData.pos_sigma = [2, 2, 5]
    }
  }
  return imageMetaData
}

export function parsePhotos (files, cb) {
  let cameras = []
  let processQueue = files
  let total = files.length
  let concurrence = 20 // 并发数
  let request = 0   // 当前正在解析的照片数
  
  return new Promise((resolve) => {
    const run = () => {
      for(let i = request;i < concurrence;i++) {
        let file = processQueue.pop()
        if (!file) {
          break
        }
        request++
        this.parsePhoto(file).then(meta_data => {
          request--
          let ext = file.split('.').pop()
          let camera = {
            width: meta_data.width,
            height: meta_data.height,
            ext,
            parameters: meta_data.pre_calib_param || null
          }
          let item = cameras.find(d => {
            return d.width === camera.width && d.height === camera.height && d.ext === camera.ext && _.isEqual(d.parameters, camera.parameters)
          })
          if (!item) {
            item = camera
            item.fileList = []
            cameras.push(item)
          }
          item.fileList.push({
            name: file.split('\\').pop(),
            filesize: meta_data.filesize,
            md5: meta_data.md5,
            filePath: file,
            meta_data
          })
          done()
        }).catch(err => {
          request--
          done()
          console.error(err)
        })
      }
    }
    const done = () => {
      if (processQueue.length) {
        run()
      } else if (!request) {
        resolve(cameras)
      }
      let parsed = total - processQueue.length - request
      if (cb) {
        cb(parsed, total)
      }
    }
    run()
  })
}
