import {BehaviorSubject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {csv} from 'd3';

import vars2facts from '../assets/data/variables2factors.json';

@Injectable({providedIn: 'root'})
export class SdmDihService {
  readonly DATA_PATH = window.location.hostname.includes('localhost')
    ? '../assets/data/normalized_data.csv'
    : './assets/data/normalized_data.csv';
  sdmData;
  //aggregatedData = {};
  firstYear: string;
  lastYear: string;
  /**
   * TODO: fill this in auto-magically
   */
  factors = [
    'aggregated',
    'http://www.semanticweb.org/attractiveness/anthropic',
    'http://www.semanticweb.org/attractiveness/economic',
    'http://www.semanticweb.org/attractiveness/natural',
    'http://www.semanticweb.org/attractiveness/social',
  ];
  domains = [];
  regions = [];
  scenarios = [];
  years = [];
  yearsLoaded = false;
  dataLoads: BehaviorSubject<boolean> = new BehaviorSubject(false);

  constructor(private httpClient: HttpClient) {
    this.loadData()
      .then(() => {
        this.years = Object.keys(this.sdmData);
        this.yearsLoaded = true;
        console.log(this.years);
        this.firstYear = this.years[0];
        this.lastYear = this.years[this.years.length - 1];
        this.regions = [
          ...new Set(
            this.sdmData[this.firstYear].map((yearData) => yearData['MODEL'])
          ),
        ];
        console.log(this.regions);
        this.scenarios = [
          ...new Set(
            this.sdmData[this.firstYear].map((yearData) => yearData['SCENARIO'])
          ),
        ];
        console.log(this.scenarios);
        this.domains = [
          ...new Set(
            this.sdmData[this.firstYear].map((yearData) => yearData['DOMAIN'])
          ),
        ];
        console.log(this.domains);
        this.dataLoads.next(true);
      })
      .catch((err) => {
        console.warn('shit happened', err);
      });
  }

  calcAggregatedIndex(regionData) {
    let weightedSum = 0;
    let sumWeight = 0;
    for (const key of Object.keys(regionData) as any) {
      if (
        key === 'MODEL' ||
        key === 'DOMAIN' ||
        key === 'SCENARIO' ||
        key === 'TIME_STEP'
      ) {
        continue;
      }
      const factorValues = regionData[key];
      let sumValue = 0;
      let n = 0;
      for (const ds of factorValues.datasets) {
        sumValue += ds.value;
        n += 1;
      }
      weightedSum += sumValue * factorValues['weight'];
      sumWeight += n * factorValues['weight'];
    }
    return weightedSum / sumWeight;
  }

  calcFactorIndex(factorData) {
    let sumValue = 0;
    let n = 0;
    for (const ds of factorData.datasets) {
      sumValue += ds.value;
      n += 1;
    }
    return sumValue / n;
  }

  async loadData() {
    const data = await csv(this.DATA_PATH); // Array of objects, each object represents a row, where key is a heading and value is the cell
    console.log(data);
    this.sdmData = {};
    for (const row of data) {
      const timeStep = row['TIME_STEP'];
      const regionData = this.splitDataByFactor(row);
      if (!this.sdmData[timeStep]) {
        this.sdmData[timeStep] = [];
      }
      this.sdmData[timeStep].push(regionData);
    }
    console.log(this.sdmData);
  }

  perc2color(perc: number): string {
    perc = perc * 100;
    let r;
    let g;
    const b = 0;
    if (perc < 50) {
      r = 255;
      g = Math.round(5.1 * perc);
    } else {
      g = 255;
      r = Math.round(510 - 5.1 * perc);
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const h = r * 0x10000 + g * 0x100 + b * 0x1;
    return `rgba(${r}, ${g}, ${b}, 0.7)`;
  }

  /**
   * Change format of each input row into a two-level structure where datasets are classified by factors
   * @param inputRegionData - row as read by the CSV reader
   * @returns data for one region in one point in time
   */
  splitDataByFactor(inputRegionData) {
    const regionData = {};
    for (const dataset of Object.keys(inputRegionData)) {
      const datasetValue = inputRegionData[dataset];
      if (['MODEL', 'DOMAIN', 'SCENARIO', 'TIME_STEP'].includes(dataset)) {
        // just copy the MODEL, DOMAIN, SCENARIO and TIME_STEP
        regionData[dataset] = datasetValue;
        continue;
      }
      const factor = vars2facts[dataset];
      // when no factor is defined for the dataset, then skip this dataset
      if (!factor) {
        continue;
      }
      if (!regionData[factor]) {
        regionData[factor] = {
          weight: 1,
          datasets: [],
        };
      }
      regionData[factor].datasets.push({
        name: dataset,
        value: parseFloat(datasetValue),
      });
    }
    for (const key of Object.keys(regionData)) {
      if (
        key === 'MODEL' ||
        key === 'DOMAIN' ||
        key === 'SCENARIO' ||
        key === 'TIME_STEP'
      ) {
        continue;
      }
      const values = regionData[key];
      if (values === undefined || values.datasets === undefined) {
        console.warn('no data for', values, regionData, key);
      }
      const index = this.calcFactorIndex(values);
      values['index'] = index;
    }
    const aggregated = this.calcAggregatedIndex(regionData);
    regionData['aggregated'] = aggregated;
    return regionData;
  }
}
