/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2017, 2019. All Rights Reserved.
 * Copyright (c) 2020 Red Hat, Inc.
 *
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 *******************************************************************************/
'use strict'

import jsYaml from 'js-yaml'
import YamlParser from '../../lib/client/yaml-helper'
import _ from 'lodash'
import R from 'ramda'

export const getParsedString = item => {
  return getStringAndParsed(item).yaml
}

export const removeMeta = obj => {
  // remove the system stuff
  const system = [
    'creationTimestamp',
    'status',
    'selfLink',
    'uid',
    'annotations',
    'livenessProbe'
  ]
  for (const key in obj) {
    if (system.indexOf(key) !== -1) {
      if (key === 'annotations') {
        const annotations = obj[key]
        let hasGitInfo = false
        //remove all but git annotations
        for (const annotation_key in annotations) {
          if (
            R.contains('apps.open-cluster-management.io/git', annotation_key)
          ) {
            hasGitInfo = true
          } else {
            //remove only annotations not related to git channel path
            delete annotations[annotation_key]
          }
        }

        if (!hasGitInfo) {
          //remove annotations completely if no git info
          delete obj[key]
        }
      } else {
        delete obj[key]
      }
    }
  }

  return obj
}

// itemKeys: members of item that get their own chart section
export const getStringAndParsed = (item, itemKeys = []) => {
  const tempItem = _.cloneDeep(item)
  //delete only system properties under the raw metadata section
  // leave others such as channel > spec > gates > annotations
  tempItem &&
    typeof tempItem === 'object' &&
    removeMeta(R.pathOr('', ['raw', 'metadata'], tempItem))

  // use this to sort the keys generated by safeDump
  const sortKeys = (a, b) => {
    if (a === 'name' && b !== 'name') {
      return -1
    } else if (a !== 'name' && b === 'name') {
      return 1
    } else if (a === 'namespace' && b !== 'namespace') {
      return -1
    } else if (a !== 'namespace' && b === 'namespace') {
      return 1
    }
    return a.localeCompare(b)
  }

  // dump parsed data into yaml sections
  let yaml,
      row = 0
  let parsed
  const yamls = []
  if (tempItem.raw) {
    yaml = jsYaml.safeDump(tempItem.raw, { sortKeys })
    // create objects from the dumped yaml to create with row #'s
    parsed = new YamlParser().parse(yaml)
    row += yaml.split('\n').length
    yamls.push(yaml)
  }

  // then dump the arrays within parsed
  itemKeys.forEach(key => {
    const arr = tempItem[key]
    if (Array.isArray(arr)) {
      parsed[key] = []
      arr.forEach((member, idx) => {
        if (member.raw) {
          yaml = jsYaml.safeDump(member.raw, { sortKeys })
          // create objects from the dumped yaml to create with row #'s
          const synced = new YamlParser().parse(yaml, row)
          synced.$r = row
          synced.$yml = yaml
          synced.$raw = member.raw
          synced.$org = item[key][idx]
          parsed[key].push(synced)
          row += yaml.split('\n').length
          yamls.push(yaml)
        }
      })
    }
  })
  return { yaml: yamls.join('---\n'), parsed }
}

export const parse = (yaml, validator, locale) => {
  let absLine = 0
  const parsed = {}
  const yamls = yaml.split('---\n')
  const exceptions = []
  // check for syntax errors
  try {
    yamls.forEach(snip => {
      if (snip) {
        const obj = jsYaml.safeLoad(snip)
        const key = _.get(obj, 'kind', 'unknown')
        let values = parsed[key]
        if (!values) {
          values = parsed[key] = []
        }
        const $synced = new YamlParser().parse(snip, absLine)
        $synced.$r = absLine
        values.push({ $raw: obj, $yml: snip, $synced })
        absLine += snip.split('\n').length
      }
    })
  } catch (e) {
    const { mark = {}, reason, message } = e
    const { line = 0, column = 0 } = mark
    exceptions.push({
      row: line + absLine - 1,
      column,
      text: _.capitalize(reason || message),
      type: 'error'
    })
  }

  // validate
  if (validator && exceptions.length === 0) {
    validator(parsed, exceptions, locale)
  }

  return { parsed, exceptions }
}

export const saveLoad = data => {
  return jsYaml.safeLoadAll(data)
}
