const bsk = require('.')

bsk.config.logLevel = 'warn'

function isProfileLegacy(profile) {
  if (profile['@type'] || profile['@context']) {
    return false
  }

  if (profile['avatar'] || profile['cover'] ||
      profile['bio'] || profile['twitter'] || profile['bitcoin'] ||
      profile['v'] || profile['facebook']) {
    return true
  }
  return false
}

function formatAccount(service_name, data) {
  if (! data.username) {
    return false
  }

  const account = {
    "@type": "Account",
    "service": service_name,
    "identifier": data["username"],
    "proofType": "http"
  }

  if (data[service_name] &&
      data[service_name]["proof"] &&
      data[service_name]["proof"]["url"]) {
    account["proofUrl"] = data[service_name]["proof"]["url"]
  }

  return account
}

function convertFromLegacy(profile) {
  if (!isProfileLegacy(profile)) {
    return profile
  }

  const images = []
  const accounts = []
  const profile_data = {
    "@type": "Person"
  }

  if (profile.name && typeof(profile.name) === 'object' &&
      profile.name.formatted) {
    profile_data.name = profile.name.formatted
  }

  if (profile.bio) {
    profile_data["description"] = profile["bio"]
  }

  if (profile.location && typeof(profile.location) === 'object' &&
      profile.location.formatted) {
    profile_data["address"] = {
      "@type": "PostalAddress",
      "addressLocality": profile["location"]["formatted"]
    }
  }

  if (profile.avatar && typeof(profile.avatar) === 'object' &&
      profile.avatar.url) {
    images.push({
      "@type": "ImageObject",
      "name": "avatar",
      "contentUrl": profile["avatar"]["url"]
    })
  }

  if (profile.cover && typeof(profile.cover) === 'object' &&
      profile.cover.url) {
    images.push({
      "@type": "ImageObject",
      "name": "cover",
      "contentUrl": profile["cover"]["url"]
    })
  }

  if (images.length > 0) {
    profile_data["image"] = images
  }

  if (profile.website && typeof(profile.website) === 'string') {
    profile_data["website"] = [{
      "@type": "WebSite",
      "url": profile["website"]
    }]
  }

  const services = ["twitter", "facebook", "github"]

  services.forEach(serviceName => {
    if (profile[serviceName]) {
      const account = formatAccount(serviceName, profile[serviceName])
      if (account) {
        accounts.push(account)
      }
    }
  })

  if (profile.bitcoin && typeof(profile.bitcoin) === 'object' &&
      profile.bitcoin.address) {
    accounts.push({
      "@type": "Account",
      "role": "payment",
      "service": "bitcoin",
      "identifier": profile["bitcoin"]["address"]
    })
  }

  if (profile.auth) {
    if (profile.auth.length > 0 && typeof(profile.auth[0]) === 'object') {
      if (profile.auth[0].publicKeychain) {
        accounts.push({
          "@type": "Account",
          "role": "key",
          "service": "bip32",
          "identifier": profile["auth"][0]["publicKeychain"]
        })
      }
    }
  }

  if (profile.pgp && typeof(profile.pgp) === 'object' &&
      profile.pgp.url && profile.pgp.fingerprint) {
    accounts.push({
      "@type": "Account",
      "role": "key",
      "service": "pgp",
      "identifier": profile["pgp"]["fingerprint"],
      "contentUrl": profile["pgp"]["url"]
    })
  }

  profile_data["account"] = accounts

  return profile_data
}

let errorImages = []

function uploadProfile(key, address, profile) {
  const profileToUpload = convertFromLegacy(profile)
  return bsk.connectToGaiaHub('https://hub.blockstack.org',
                              key.slice(0, 64))
    .then(connectionInfo => {
      const urlStart = connectionInfo['url_prefix'] + connectionInfo['address'] + '/'
      let imagePromises = []
      if (profileToUpload.image) {
        let index = 0
        imagePromises = profileToUpload.image.map( original => {
          return Promise.resolve().then(() => {
            const landingPath = original.contentUrl.split('/').pop() + '.' + index
            index += 1
            return fetch(original.contentUrl)
              .then(resp => {
                const contentType = resp.headers.get('content-type')
                return resp.buffer()
                  .then(content => bsk.uploadToGaiaHub(landingPath, content, connectionInfo, contentType))
              })
              .then(landingUrl => {
                return Object.assign({}, original, { contentUrl: landingUrl })
              })
          })
            .catch(() => {
              errorImages.push(address)
              return false
            })
        })
      }
      return Promise.all(imagePromises)
        .then(images => {
          if (images.length > 0) {
            profileToUpload.image = images.filter(x => x)
          }
          const privateKey = key.slice(0, 64)
          const publicKey = bsk.getPublicKeyFromPrivate(privateKey)
          const token = bsk.signProfileToken(profileToUpload, privateKey, { publicKey })
          const tokenRecord = bsk.wrapProfileToken(token)
          const tokenRecords = [tokenRecord]
          const toUpload = JSON.stringify(tokenRecords, null, 2)

          return bsk.uploadToGaiaHub('profile.json', toUpload, connectionInfo, 'application/json')
        })
    })
}

const namesAndKeys = require('/home/aaron/devel/onename-spin-down/data/names_and_keys.json')
const profiles = require('/home/aaron/devel/onename-spin-down/data/profiles_to_copy.json')

async function loadAllAndProcess() {
  let profMap = {}
  profiles.forEach(entry => {
    profMap[entry.username] = entry.profile
  })

  namesAndKeys.forEach(entry => {
    const profile = profMap[entry.name]
    if (!profile) {
      throw new Error('Failed to copy name ' + entry.name)
    }
  })

  for (let i = 50000; i < namesAndKeys.length; i++) {
    const entry = namesAndKeys[i]
    if (entry.name !== "aubreykilian" && entry.name !== "davegreenway") {
      continue
    }
    const profile = profMap[entry.name]
    const key = entry.ownerKey
    const address = entry.ownerAddress
    try {
      await uploadProfile(key, address, profile)
    } catch (error) {
      console.error(error.stack)
      console.error('ERROR on: ' + entry.name)
    }
    if (i % 10 === 0) {
      process.stdout.write(".")
    }
    if (i % 250 === 0) {
      console.log(i)
    }
  }

  console.error("IMAGE ERRORS ON:")
  console.error(JSON.stringify(errorImages))
}


loadAllAndProcess()
