import React, { Component } from 'react';
import { Button, ButtonGroup, Form, InputGroup, InputGroupAddon, Input } from 'reactstrap';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus, faMinus, faChartArea, faChartLine } from '@fortawesome/free-solid-svg-icons';
import TimeInput from './TimeInput';
import { parseDuration, formatDuration } from '../../utils';

interface GraphControlsProps {
  range: number;
  endTime: number | null;
  useLocalTime: boolean;
  resolution: number | null;
  stacked: boolean;
  showExemplars: boolean;

  onChangeRange: (range: number) => void;
  onChangeEndTime: (endTime: number | null) => void;
  onChangeResolution: (resolution: number | null) => void;
  onChangeStacking: (stacked: boolean) => void;
  onChangeShowExemplars: (show: boolean) => void;
}

class GraphControls extends Component<GraphControlsProps> {
  private rangeRef = React.createRef<HTMLInputElement>();
  private resolutionRef = React.createRef<HTMLInputElement>();

  rangeSteps = [
    1,
    10,
    60,
    5 * 60,
    15 * 60,
    30 * 60,
    60 * 60,
    2 * 60 * 60,
    6 * 60 * 60,
    12 * 60 * 60,
    24 * 60 * 60,
    48 * 60 * 60,
    7 * 24 * 60 * 60,
    14 * 24 * 60 * 60,
    28 * 24 * 60 * 60,
    56 * 24 * 60 * 60,
    112 * 24 * 60 * 60,
    182 * 24 * 60 * 60,
    365 * 24 * 60 * 60,
    730 * 24 * 60 * 60,
  ].map(s => s * 1000);

  onChangeRangeInput = (rangeText: string): void => {
    const range = parseDuration(rangeText);
    if (range === null) {
      this.changeRangeInput(this.props.range);
    } else {
      this.props.onChangeRange(range);
    }
  };

  changeRangeInput = (range: number): void => {
    this.rangeRef.current!.value = formatDuration(range);
  };

  increaseRange = (): void => {
    for (const range of this.rangeSteps) {
      if (this.props.range < range) {
        this.changeRangeInput(range);
        this.props.onChangeRange(range);
        return;
      }
    }
  };

  decreaseRange = (): void => {
    for (const range of this.rangeSteps.slice().reverse()) {
      if (this.props.range > range) {
        this.changeRangeInput(range);
        this.props.onChangeRange(range);
        return;
      }
    }
  };

  componentDidUpdate(prevProps: GraphControlsProps) {
    if (prevProps.range !== this.props.range) {
      this.changeRangeInput(this.props.range);
    }
    if (prevProps.resolution !== this.props.resolution) {
      this.resolutionRef.current!.value = this.props.resolution !== null ? this.props.resolution.toString() : '';
    }
  }

  render() {
    return (
      <Form inline className="graph-controls" onSubmit={e => e.preventDefault()}>
        <InputGroup className="range-input" size="sm">
          <InputGroupAddon addonType="prepend">
            <Button title="Decrease range" onClick={this.decreaseRange}>
              <FontAwesomeIcon icon={faMinus} fixedWidth />
            </Button>
          </InputGroupAddon>

          <Input
            defaultValue={formatDuration(this.props.range)}
            innerRef={this.rangeRef}
            onBlur={() => this.onChangeRangeInput(this.rangeRef.current!.value)}
            onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) =>
              e.key === 'Enter' && this.onChangeRangeInput(this.rangeRef.current!.value)
            }
          />

          <InputGroupAddon addonType="append">
            <Button title="Increase range" onClick={this.increaseRange}>
              <FontAwesomeIcon icon={faPlus} fixedWidth />
            </Button>
          </InputGroupAddon>
        </InputGroup>

        <TimeInput
          time={this.props.endTime}
          useLocalTime={this.props.useLocalTime}
          range={this.props.range}
          placeholder="End time"
          onChangeTime={this.props.onChangeEndTime}
        />

        <Input
          placeholder="Res. (s)"
          className="resolution-input"
          defaultValue={this.props.resolution !== null ? this.props.resolution.toString() : ''}
          innerRef={this.resolutionRef}
          onBlur={() => {
            const res = parseInt(this.resolutionRef.current!.value);
            this.props.onChangeResolution(res ? res : null);
          }}
          bsSize="sm"
        />

        <ButtonGroup className="stacked-input" size="sm">
          <Button
            title="Show unstacked line graph"
            onClick={() => this.props.onChangeStacking(false)}
            active={!this.props.stacked}
          >
            <FontAwesomeIcon icon={faChartLine} fixedWidth />
          </Button>
          <Button title="Show stacked graph" onClick={() => this.props.onChangeStacking(true)} active={this.props.stacked}>
            <FontAwesomeIcon icon={faChartArea} fixedWidth />
          </Button>
        </ButtonGroup>

        <ButtonGroup className="show-exemplars" size="sm">
          {this.props.showExemplars ? (
            <Button title="Hide exemplars" onClick={() => this.props.onChangeShowExemplars(false)} active={true}>
              Hide Exemplars
            </Button>
          ) : (
            <Button title="Show exemplars" onClick={() => this.props.onChangeShowExemplars(true)} active={false}>
              Show Exemplars
            </Button>
          )}
        </ButtonGroup>
      </Form>
    );
  }
}

export default GraphControls;
