import url = require('url');

import { SpadeEventData } from "../types/SpadeEventData";
import { continentMap, countryNameMap, regionMap } from "../geo";
import { regex } from "../regex";

import { IPoint } from 'influx'
import { InfluxTags, InfluxFields } from "../types/influx";

export class SpadeDataPoint {
  database: string;

  raw: SpadeEventData;
  timestamp: number;

  continent: string;
  country: string;
  region: string;
  city: string;

  constructor(readonly measurement: string, fields: SpadeEventData) {
    this.raw = fields; // Debug Data
    this.database = `demeter_${measurement}`
    this.timestamp = new Date(fields.time_utc).getTime() * 1000;

    // Tags
    this.continent = continentMap[fields.country] ? continentMap[fields.country].continent : `Unknown Country Code: ${fields.country}`;
    this.country = countryNameMap[fields.country] ? countryNameMap[fields.country].name : `Unknown Country Code: ${fields.country}`;
    this.region = regionMap[`${fields.country}:${fields.region}`] ? regionMap[`${fields.country}:${fields.region}`].region_name : '';

    // Fields
    this.city = fields.city;
  }

  parseBool(value: string): boolean {
    try {
      return JSON.parse(value)
    } catch (error) {
      if (error instanceof SyntaxError) {
        return false
      } else {
        throw error;
      }
    }
  }

  parseDomain(value: string): string {
    value = value.charAt(value.length - 1) == '.' ? value.substr(0, value.length - 1) : value;
    return regex.IsValidDomain.test(value) ? value : 'other';
  }

  parseURL(value: string): string {
    if (typeof (value) == "undefined" || value == null) {
      return ''; // These are known failures later, and don't matter, skipping the noisy logging.
    }

    try {
      let original: url.Url = url.parse(value);
      return `${original.protocol}//${original.hostname}${original.path}`
    } catch (error) {
      if (error instanceof TypeError) {
        console.error(`Unable to parse "${value}". Was expecting valid URL string. Returning an empty string.`);
        return '';
      } else {
        throw error;
      }
    }
  }

  filteredTags(): InfluxTags {
    const originals = this.getTags()
    const filtered: InfluxTags = {}

    for (let key in originals) {
      switch (originals[key]) {
        case '':
        case undefined:
        case null:
          continue;
        default:
          filtered[key] = originals[key].replace(/\\/g, '')
      }
    }

    return filtered
  }

  filteredFields(): InfluxFields {
    const originals = this.getFields()
    const filtered: InfluxFields = {}

    for (let key in originals) {
      switch (originals[key]) {
        case undefined:
          continue;
        default:
          if (typeof (originals[key]) != "string" && typeof (originals[key]) != "boolean" && isNaN(+originals[key])) {
            filtered[key] = 0;
          } else {
            filtered[key] = originals[key];
          }
      }
    }

    return filtered
  }

  toInflux(): IPoint {
    const data = {
      measurement: this.measurement,
      timestamp: this.timestamp,
      tags: this.filteredTags(),
      fields: this.filteredFields()
    }

    return data;
  }

  getFields(): InfluxFields {
    return {
      city: this.city,
      region: this.region
    }
  }

  getTags(): InfluxTags {
    return {
      continent: this.continent,
      country: this.country
    }
  }
}
