/* global Flash */
import d3 from 'd3';
import {
  dateFormat,
  timeFormat,
} from './constants';

export default class Deployments {
  constructor(width, height) {
    this.width = width;
    this.height = height;

    this.endpoint = document.getElementById('js-metrics').dataset.deploymentEndpoint;

    this.createGradientDef();
  }

  init(chartData) {
    this.chartData = chartData;

    this.x = d3.time.scale().range([0, this.width]);
    this.x.domain(d3.extent(this.chartData, d => d.time));

    this.charts = d3.selectAll('.prometheus-graph');

    this.getData();
  }

  getData() {
    $.ajax({
      url: this.endpoint,
      dataType: 'JSON',
    })
    .fail(() => new Flash('Error getting deployment information.'))
    .done((data) => {
      this.data = data.deployments.reduce((deploymentDataArray, deployment) => {
        const time = new Date(deployment.created_at);
        const xPos = Math.floor(this.x(time));

        time.setSeconds(this.chartData[0].time.getSeconds());

        if (xPos >= 0) {
          deploymentDataArray.push({
            id: deployment.id,
            time,
            sha: deployment.sha,
            tag: deployment.tag,
            ref: deployment.ref.name,
            xPos,
          });
        }

        return deploymentDataArray;
      }, []);

      this.plotData();
    });
  }

  plotData() {
    this.charts.each((d, i) => {
      const svg = d3.select(this.charts[0][i]);
      const chart = svg.select('.graph-container');
      const key = svg.node().getAttribute('graph-type');

      this.createLine(chart, key);
      this.createDeployInfoBox(chart, key);
    });
  }

  createGradientDef() {
    const defs = d3.select('body')
      .append('svg')
      .attr({
        height: 0,
        width: 0,
      })
      .append('defs');

    defs.append('linearGradient')
      .attr({
        id: 'shadow-gradient',
      })
      .append('stop')
      .attr({
        offset: '0%',
        'stop-color': '#000',
        'stop-opacity': 0.4,
      })
      .select(this.selectParentNode)
      .append('stop')
      .attr({
        offset: '100%',
        'stop-color': '#000',
        'stop-opacity': 0,
      });
  }

  createLine(chart, key) {
    chart.append('g')
      .attr({
        class: 'deploy-info',
      })
      .selectAll('.deploy-info')
      .data(this.data)
      .enter()
      .append('g')
      .attr({
        class: d => `deploy-info-${d.id}-${key}`,
        transform: d => `translate(${Math.floor(d.xPos) + 1}, 0)`,
      })
      .append('rect')
      .attr({
        x: 1,
        y: 0,
        height: this.height + 1,
        width: 3,
        fill: 'url(#shadow-gradient)',
      })
      .select(this.selectParentNode)
      .append('line')
      .attr({
        class: 'deployment-line',
        x1: 0,
        x2: 0,
        y1: 0,
        y2: this.height + 1,
      });
  }

  createDeployInfoBox(chart, key) {
    chart.selectAll('.deploy-info')
      .selectAll('.js-deploy-info-box')
      .data(this.data)
      .enter()
      .select(d => document.querySelector(`.deploy-info-${d.id}-${key}`))
      .append('svg')
      .attr({
        class: 'js-deploy-info-box hidden',
        x: 3,
        y: 0,
        width: 92,
        height: 60,
      })
      .append('rect')
      .attr({
        class: 'rect-text-metric deploy-info-rect rect-metric',
        x: 1,
        y: 1,
        rx: 2,
        width: 90,
        height: 58,
      })
      .select(this.selectParentNode)
      .append('g')
      .attr({
        transform: 'translate(5, 2)',
      })
      .append('text')
      .attr({
        class: 'deploy-info-text text-metric-bold',
      })
      .text(Deployments.refText)
      .select(this.selectParentNode)
      .append('text')
      .attr({
        class: 'deploy-info-text',
        y: 18,
      })
      .text(d => dateFormat(d.time))
      .select(this.selectParentNode)
      .append('text')
      .attr({
        class: 'deploy-info-text text-metric-bold',
        y: 38,
      })
      .text(d => timeFormat(d.time));
  }

  static toggleDeployTextbox(deploy, key, showInfoBox) {
    d3.selectAll(`.deploy-info-${deploy.id}-${key} .js-deploy-info-box`)
      .classed('hidden', !showInfoBox);
  }

  mouseOverDeployInfo(mouseXPos, key) {
    if (!this.data) return false;

    let dataFound = false;

    this.data.forEach((d) => {
      if (d.xPos >= mouseXPos - 10 && d.xPos <= mouseXPos + 10 && !dataFound) {
        dataFound = d.xPos + 1;

        Deployments.toggleDeployTextbox(d, key, true);
      } else {
        Deployments.toggleDeployTextbox(d, key, false);
      }
    });

    return dataFound;
  }

  /* `this` is bound to the D3 node */
  selectParentNode() {
    return this.parentNode;
  }

  static refText(d) {
    return d.tag ? d.ref : d.sha.slice(0, 6);
  }
}
