import React, { Component } from 'react';

import Nav from './Nav'; import Graph from './Graph'; import RequestsBlock from './RequestsBlock' import MetricsBlock from './MetricsBlock'; import {allMetricsList, allRefreshIntervals, allTimeframes, defaultOverviewMetrics, defaultGraphMetrics} from './Constants';

interface AppProps {}

export interface AppState {

fullscreen: Boolean;
showNav: Boolean;
metrics: any;
frequency: number;
timeframe: number;
partition: String;
metricsUrl: String;
graphMetricsList: any[];
overviewMetricsList: any[];
timeoutFunction: any;
error: String;

}

export function metricValueToLabel(value: String): String | undefined {

const foundMetric = allMetricsList.find(metricHash => metricHash.value === value)
if (foundMetric) {
  return foundMetric.label
}

}

export function metricLabelToValue(label: String): String | undefined {

const foundMetric = allMetricsList.find(metricHash => metricHash.label === label)
if (foundMetric) {
  return foundMetric.value
}

}

var store = require('store');

export default class App extends Component<AppProps, AppState> {

constructor(props: AppProps) {
  super(props);
  this.state = {
    error:               "",
    showNav:             false,
    metrics:             { simple: {}, partitioned: {} },
    timeoutFunction:     setTimeout(() => this.fetchByTimeout(), allRefreshIntervals[0].value),
    fullscreen:          store.get("fullscreen"),
    metricsUrl:          store.get("metricsUrl")          || "/dashboard/metrics/aggregate",
    frequency:           store.get("frequency")           || allRefreshIntervals[0].value,
    timeframe:           store.get("timeframe")           || allTimeframes[3].value,
    partition:           store.get("partition")           || "minute",
    overviewMetricsList: store.get("overviewMetricsList") || defaultOverviewMetrics,
    graphMetricsList:    store.get("graphMetricsList")    || defaultGraphMetrics,
  };

  this.fetchData                 = this.fetchData.bind(this)
  this.changeFrequency           = this.changeFrequency.bind(this)
  this.changeTimeframe           = this.changeTimeframe.bind(this)
  this.changeMetricsUrl          = this.changeMetricsUrl.bind(this)
  this.toggleFullscreen          = this.toggleFullscreen.bind(this)
  this.toggleNav                 = this.toggleNav.bind(this)
  this.changeOverviewMetricsList = this.changeOverviewMetricsList.bind(this)
  this.changeGraphMetricsList    = this.changeGraphMetricsList.bind(this)
}

componentWillUnmount(){
  this.clearTimeoutFunction()
}

render() {
  let metricsBlockData = Object.assign({}, this.state.metrics.simple);
  delete metricsBlockData.requests;

  const metricsBlocks = Object.entries(metricsBlockData).map(
    ([name, value]) => {
      return <MetricsBlock key={name} name={name} metrics={value}/>
    }
  )

  let graphData = null;

  let partitionedMetricsSize = Object.keys(this.state.metrics.partitioned).length

  if (partitionedMetricsSize > 0) {

    let lines = this.intersection(Object.keys(this.state.metrics.partitioned[0]), this.state.graphMetricsList.map(m => m.value))

    graphData = lines.map((line: any) => {
      return {
        id: metricValueToLabel(line),
        data: this.state.metrics.partitioned.map((hash: any) => {
          return {
            x: this.formatTimestamp(hash.timestamp),
            y: hash[line]
            }
          }
        ).filter((hash: any) => typeof(hash.y) === "number")
      }
    });
  }

  return (
    <div className="App">
      <div className={this.state.fullscreen ? "container-fluid" : "container"}>
        <div className={this.state.error.length ? "alert alert-danger error-message" : "hidden"}>{this.state.error}</div>
        <nav className="navbar navbar-light bg-light rounded">
          <span className="navbar-brand">Ezmetrics | Dashboard</span>
          <div className="col"><button className="btn btn-outline-secondary fullscreen" onClick={this.toggleFullscreen}>↹</button></div>
          <button onClick={this.toggleNav} className="btn btn-outline-secondary" type="submit">Settings</button>
          <Nav
            changeFrequency={this.changeFrequency}
            changeTimeframe={this.changeTimeframe}
            changeMetricsUrl={this.changeMetricsUrl}
            toggleFullscreen={this.toggleFullscreen}
            changeGraphMetricsList={this.changeGraphMetricsList}
            changeOverviewMetricsList={this.changeOverviewMetricsList}
            state={this.state}
           />
        </nav>
        {this.state.metrics.simple.requests && <RequestsBlock data={this.state.metrics.simple.requests} state={this.state}/>}
        <div className="row">{metricsBlocks}</div>
        <div className="row">
          <div className="col">
            {graphData && graphData.length !== 0 && <Graph data={graphData} state={this.state}/> }
          </div>
        </div>
      </div>
    </div>
  );
}

formatTimestamp(timestamp: number): string {
  return new Date(timestamp * 1000).toLocaleTimeString("en-GB")
}

fetchByTimeout() {
  this.clearTimeoutFunction()
  this.fetchData()
  this.setState({timeoutFunction: setTimeout(() => this.fetchByTimeout(), this.state.frequency)});
}

fetchData() {
  const overviewMetrics = this.state.overviewMetricsList.map(m => m.value).join(",")
  const graphMetrics    = this.state.graphMetricsList.map(m => m.value).join(",")

  fetch(`${this.state.metricsUrl}?interval=${this.state.timeframe}&partition=${this.state.partition}&overview_metrics=${overviewMetrics}&graph_metrics=${graphMetrics}`)
  .then(res => res.json())
  .then((data) => this.setState({metrics: data, error: ""}))
  .catch(error => this.setState({error: "Fetching error: " + error.message + "."}))
}

changeFrequency(frequencyValue: number) {
  store.set("frequency", frequencyValue);
  this.setState({frequency: frequencyValue});
  this.fetchByTimeout()
}

changeTimeframe(timeframeValue: number) {
  var partition = "minute";

  if (timeframeValue < 121) {
    partition = "second";
  } else if (timeframeValue < 3601) {
    partition = "minute";
  } else {
    partition = "hour";
  }

  store.set("timeframe", timeframeValue);
  store.set("partition", partition);

  this.setState({timeframe: timeframeValue, partition: partition});
  this.fetchByTimeout()
}

changeOverviewMetricsList(metricsList: String[]) {
  store.set("overviewMetricsList", metricsList)
  this.setState({overviewMetricsList: metricsList});
}

changeGraphMetricsList(metricsList: String[]) {
  store.set("graphMetricsList", metricsList)
  this.setState({graphMetricsList: metricsList});
}

changeMetricsUrl(metricsUrl: String) {
  store.set("metricsUrl", metricsUrl);
  this.setState({metricsUrl: metricsUrl});
}

toggleFullscreen() {
  store.set("fullscreen", !this.state.fullscreen)

  this.setState(prevState => ({
    fullscreen: !prevState.fullscreen
  }));
}

toggleNav() {
  this.setState(prevState => ({
    showNav: !prevState.showNav
  }));
}

clearTimeoutFunction(){
  window.clearTimeout(this.state.timeoutFunction);
}

intersection(a1: String[], a2: String[]) {
  return a1.filter(x => a2.indexOf(x) > -1)
}

}