import { IParser } from "../../interfaces/IParser";
import { Csv } from "../../models/Csv";

export class CsvParserService implements IParser {
  #csv: Csv;

  constructor(csv: Csv) {
    this.#csv = csv;
  }
  parse() {
    const mp: Map<any, any> = this.#getAllData();
    let json: any = {};
    json = this.#mapToJson(mp, json);
    return json;
  }
  get() {
    return this.#csv;
  }
  #mapToJson(mp: Map<any, any>, json: any): any {
    Array.from(mp.entries()).forEach(([key, value]) => {
      if (value instanceof Map) {
        json[key] = {};
        json[key] = this.#mapToJson(value, json[key]);
      } else {
        json[key] = value;
      }
    });
    return json;
  }
  #getAllData(): Map<any, any> {
    let mp: Map<any, any> = new Map<any, any>();
    const rows: string[][] = this.#csv.makeRows().getRows();
    rows.forEach((row) => {
      const headers: string[] = this.#csv.getHeaders();
      let tempMp: Map<any, any> = new Map<any, any>();
      headers.forEach((header, index) => {
        tempMp = this.#getData(row[index], header, tempMp);
      });
      if (rows.length > 1) mp.set(row[0], tempMp);
      else mp = new Map<any, any>(tempMp.entries());
    });
    return mp;
  }
  #getData(
    value: any,
    path: string,
    mp: Map<any, any> = new Map<any, any>()
  ): Map<any, any> {
    if (value == undefined) return mp;
    if (path.includes(".")) {
      const current: string = path.substring(0, path.indexOf("."));
      const newPath: string = path.substring(
        path.indexOf(".") + 1,
        path.length
      );
      if (!mp.has(current)) mp.set(current, new Map<any, any>());
      const newMp: Map<any, any> = this.#getData(
        value,
        newPath,
        mp.get(current)
      );
      mp.set(current, newMp);
      return mp;
    }
    if (value == undefined || typeof value == "object") {
      throw Error("There is an error in your headers they are not accurate");
    }
    mp.set(path, value);
    return mp;
  }
}
