import * as d3Fetch from 'd3-fetch'

const dataSrc = {
  disputes: './data/20190801-disputes.csv',
  countries: './data/20190731-countries.csv'
}

const num_fields = [
  'dsno',
  'year',
  'has_multiple',
  'the_flag',
  'ascension_year',
  'is_involved'
]
const countries_fields = ['respondent', 'complainant']
const list_fields = ['third_parties', 'affected_areas', 'issue']

async function parseData() {
  const countriesPromise = fetchCSV(dataSrc.countries)
  const disputesPromise = fetchCSV(dataSrc.disputes)

  let data = Promise.all([countriesPromise, disputesPromise]).then(res => {
    const [countriesData, disputesData] = res

    const countriesList = getInvolvedCountries(countriesData)

    let dataset = {
      all_disputes: disputesData,
      total_disputes: disputesData.length,
      countries: countriesList,
      disputes: convertCountriesArrayToObj(countriesData)
    }

    const multipleCountryFields = [
      'third_parties',
      'complainant_list',
      'respondent_list'
    ]

    // Group Disputes By Country
    for (let row of disputesData) {
      for (let field of multipleCountryFields) {
        row[field + '_names'] = assignCountryNames(row[field], dataset.disputes)
      }

      for (let primary of countries_fields) {
        const iso = row[primary + '_iso']

        row[primary] = assignCountryNames(
          row[primary + '_iso'],
          dataset.disputes
        )

        // Cases where multiple countries are involved are handled later on in the loop.
        if (iso === 'MULTI') {
          continue
        }

        dataset.disputes[iso].disputes.all.num_disputes++
        dataset.disputes[iso].disputes.all['num_' + primary]++

        if (row[primary + '_list'].length > 0) {
          for (let country of row[primary + '_list']) {
            dataset.disputes[country].disputes.all.num_disputes++
            dataset.disputes[country].disputes.all['num_' + primary]++
          }
        }

        // Look at the complementary row to update the counts for the countries our primary country has been involved with.
        let secondary = 'complainant'
        if (primary === secondary) {
          secondary = 'respondent'
        }

        let secondaryList = [row[secondary + '_iso']]
        if (row[secondary + '_list'].length > 0) {
          secondaryList = row[secondary + '_list']
        }

        for (let country of secondaryList) {
          const secondaryISO = country
          const secondaryName = assignCountryNames(country, dataset.disputes)

          // Increment the count for the secondary country
          dataset.disputes[iso].disputes = linkSecondaryCountry(
            dataset.disputes[iso],
            secondaryISO,
            secondaryName
          )

          dataset.disputes[iso].disputes[secondaryISO].num_disputes++
          dataset.disputes[iso].disputes[secondaryISO]['num_' + primary]++

          // For cases where multiple countries were involved, we need to link them together so the dispute is counted for both countries.
          if (row.has_multiple) {
            dataset.disputes[secondaryISO].disputes = linkSecondaryCountry(
              dataset.disputes[secondaryISO],
              iso,
              row[primary]
            )

            dataset.disputes[secondaryISO].disputes.all.num_disputes++
            dataset.disputes[secondaryISO].disputes.all['num_' + secondary]++

            dataset.disputes[secondaryISO].disputes[iso].num_disputes++
            dataset.disputes[secondaryISO].disputes[iso]['num_' + secondary]++
          }
        }
      }
    }

    dataset.countries.sort((a, b) => a.label.localeCompare(b.label))

    return dataset
  })

  return data
}

function linkSecondaryCountry(primaryCountryObj, secondaryISO, secondaryName) {
  if (primaryCountryObj.disputes[secondaryISO]) {
    return primaryCountryObj.disputes
  }

  primaryCountryObj.disputes[secondaryISO] = {
    value: secondaryISO,
    label: secondaryName,
    num_disputes: 0,
    num_complainant: 0,
    num_respondent: 0
  }

  primaryCountryObj.num_diff_countries++

  let label = 'Economies'
  if (primaryCountryObj.num_diff_countries == 1) {
    label = 'Economy'
  }
  primaryCountryObj.disputes['all'].label =
    primaryCountryObj.num_diff_countries + ' ' + label

  return primaryCountryObj.disputes
}

function getInvolvedCountries(data) {
  return data
    .map(d => ({
      value: d.iso,
      label: d.country,
      is_involved: d.is_involved
    }))
    .filter(d => d.is_involved)
}

function convertCountriesArrayToObj(data) {
  const MULTI = {
    iso: 'MULTI',
    country: 'Multiple Participants',
    num_diff_countries: 0,
    disputes: {
      all: {
        value: 'all',
        label: null,
        num_disputes: 0,
        num_complainant: 0,
        num_respondent: 0
      }
    }
  }

  return data.reduce(
    (acc, curr) => {
      acc[curr.iso] = {
        ...curr,
        num_diff_countries: 0,
        disputes: {
          all: {
            value: 'all',
            label: null,
            num_disputes: 0,
            num_complainant: 0,
            num_respondent: 0
          }
        }
      }
      return acc
    },
    { MULTI }
  )
}

function assignCountryNames(data, names) {
  if (!data) {
    return null
  }

  if (Array.isArray(data)) {
    return data.map(d => names[d].country)
  }

  return names[data].country
}

function fetchCSV(src) {
  return d3Fetch.csv(src, d => {
    d.respondent_list = []
    d.complainant_list = []

    for (var i in d) {
      if (num_fields.includes(i)) {
        d[i] = +d[i]
      }

      if (list_fields.includes(i) && d[i].includes(';')) {
        d[i] = d[i].split(';').map(item => item.trim())
      }
    }

    if (d.has_multiple) {
      for (let column of countries_fields) {
        if (d[column + '_iso'].includes(';')) {
          d[column + '_list'] = d[column + '_iso']
            .split(';')
            .map(item => item.trim())
          d[column + '_iso'] = 'MULTI'
        }
      }
    }

    return d
  })
}

export default parseData
