import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import $ from 'jquery';
import noop from 'lodash/noop';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import './pie-chart.less';
import * as WidgetHelper from './_helper';

export default class TsdevPieChart extends Component {

    constructor(props) {
        super(props);
        this.chartRef = React.createRef();
    }

    componentDidMount() {
        this.renderChart();
    }

    /* istanbul ignore next */
    componentDidUpdate() {
        $('.tsdev-pie-chart-legend').empty();
        this.renderChart();
    }

    renderChart() {
        const {
            id,
            width,
            colorRange,
            showSortedValues,
            sortDirection,
            startAngle,
            endAngle,
            radius,
            showTooltips,
            showInnerLabels,
            showOuterLabels,
            strokeColor,
            strokeWidth,
            dataSet,
            showLegend,
            legendColor,
            onSegmentClick,
            xOffset,
            yOffset,
            rotation,
            height,
            tooltipType,
            decimals
        } = this.props;
        const transform = `translate (${xOffset + (width / 2)},${yOffset + (height / 2)}) rotate(${rotation}, ${0}, ${0})`;
        const color = WidgetHelper.handleColorRange(colorRange);
        const tooltipContainer = WidgetHelper.prepareTooltipContainer(id);
        const tooltipContainerLegendColor = WidgetHelper.prepareTooltipColor(tooltipContainer);
        const tooltipText = WidgetHelper.prepareTooltipText(tooltipContainer);

        $(this.chartRef.current).empty();
        const svg = d3.select(ReactDOM.findDOMNode(this.chartRef.current))
            .append('svg')
            .attr('class', 'chart-svg')
            .attr('width', width)
            .attr('height', height)
            .append('g')
            .attr('class', 'tsdev-chart-svg-base-group')
            .attr('transform', transform)
            .datum(dataSet);
        const pie = d3.layout.pie()
            .value((d) => {
                return d.value;
            })
            .sort(showSortedValues ? /* istanbul ignore next */ (sortDirection === 'asc' ? WidgetHelper.handleAscSort : WidgetHelper.handleDescSort) : null)
            .startAngle(startAngle * (Math.PI / 180))
            .endAngle(endAngle * (Math.PI / 180));
        const arcs = svg.selectAll('g.slice')
            .data(pie)
            .enter()
            .append('g')
            .attr('class', 'slice');
        const arc = d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius);

        arcs.append('path')
            .attr('fill', (d, i) => {
                if (showLegend) {
                    const legendItem = d3.select(`#tsdev-pie-chart-legend-${id}`);

                    legendItem.append('div')
                        .attr('class', 'legend-item-color')
                        .style('background-color', color(i))
                        .style('border-color', legendColor);
                    legendItem.append('div')
                        .attr('class', 'legend-item-text')
                        .style('color', legendColor)
                        .text(d.data.label + ': ' + d.data.value);
                }

                return color(i);
            })
            .style('stroke', strokeColor)
            .style('stroke-width', strokeWidth)
            .attr('d', arc)
            .attr('data-legend', (d) => {
                return d.data.label;
            })
            .on('mouseover', /* istanbul ignore next */(d, i) => {
                if (showTooltips) {
                    const valueSum = WidgetHelper.calculateValueSum(dataSet);

                    let tooltip = '';

                    switch (tooltipType.toLowerCase()) {
                        case 'label': tooltip = d.data.label;
                            break;
                        case 'value': tooltip = d.data.value;
                            break;
                        case 'percent': tooltip = (d.data.value * 100 / valueSum).toFixed(decimals) + ' %';
                            break;
                        case 'labelpercent': tooltip = d.data.label + ': ' + (d.data.value * 100 / valueSum).toFixed(decimals) + ' %';
                            break;
                        default: tooltip = d.data.label + ': ' + d.data.value;
                    }
                    tooltipContainer.transition()
                        .duration(150)
                        .style('opacity', 0.8);
                    tooltipContainerLegendColor.attr('style', () => {
                        return 'background-color: ' + color(i) + ';';
                    });
                    tooltipText.html(tooltip);
                    tooltipContainer
                        .style('left', (d3.event.pageX) + 'px')
                        .style('top', (d3.event.pageY - 10) + 'px');
                }
            })
            .on('mouseout', /* istanbul ignore next */() => {
                tooltipContainer.transition()
                    .duration(500)
                    .style('opacity', 0);
            })
            .on('click', /* istanbul ignore next */(d) => {
                onSegmentClick(d.data);
            });

        if (showInnerLabels) {
            const valueSum = WidgetHelper.calculateValueSum(dataSet);
            const labelElement = svg.selectAll('.arc-inner-label')
                .data(pie(dataSet))
                .enter()
                .append('g')
                .attr('class', 'arc-inner-label');

            WidgetHelper.renderInnerArcLabels(this.props, labelElement, arc, valueSum);
        }

        if (showOuterLabels) {
            const valueSum = WidgetHelper.calculateValueSum(dataSet);
            const labelElement = svg.selectAll('.arc-outer-label')
                .data(pie(dataSet))
                .enter()
                .append('g')
                .attr('class', 'arc-outer-label');

            WidgetHelper.renderOuterArcLabels(this.props, labelElement, arc, valueSum);
        }

    }

    render() {
        const {
            id,
            subClass,
            width,
            height,
            legendHeight,
            showLegend,
            backgroundColor,
            backgroundColorLegend,
            legendColor
        } = this.props;
        const className = classnames('tsdev-pie-chart', subClass);
        const inlineStyle = {
            width: width + 2,
            height: height + legendHeight + 15
        };
        const inlineStyleLegend = {
            width: width,
            height: legendHeight,
            display: showLegend ? 'block' : 'none',
            backgroundColor: backgroundColorLegend,
            color: legendColor
        };
        const inlineStyleWrapper = {
            backgroundColor: backgroundColor
        };

        return (
            <div id={id}
                className={className}
                style={inlineStyle}>
                <div ref={this.chartRef}
                    style={inlineStyleWrapper}
                    className="chart-wrapper" />
                <div id={`tsdev-pie-chart-legend-${id}`}
                    className="tsdev-pie-chart-legend"
                    style={inlineStyleLegend} />
            </div>
        );
    }
}

TsdevPieChart.propTypes = {
    backgroundColor: PropTypes.string,
    backgroundColorLegend: PropTypes.string,
    colorRange: PropTypes.arrayOf(PropTypes.string),
    dataSet: PropTypes.arrayOf(PropTypes.object),
    decimals: PropTypes.number,
    endAngle: PropTypes.number,
    height: PropTypes.number,
    id: PropTypes.string,
    innerLabelColor: PropTypes.string,
    innerLabelSize: PropTypes.number,
    innerLabelType: PropTypes.string,
    labelLineColor: PropTypes.string,
    labelLineDotColor: PropTypes.string,
    labelLineDotRadius: PropTypes.number,
    labelLineWidth: PropTypes.number,
    legendColor: PropTypes.string,
    legendHeight: PropTypes.number,
    onSegmentClick: PropTypes.func,
    outerLabelColor: PropTypes.string,
    outerLabelOffset: PropTypes.number,
    outerLabelSize: PropTypes.number,
    outerLabelType: PropTypes.string,
    radius: PropTypes.number,
    rotation: PropTypes.number,
    showInnerLabels: PropTypes.bool,
    showLabelLine: PropTypes.bool,
    showLabelLineDot: PropTypes.bool,
    showLegend: PropTypes.bool,
    showOuterLabels: PropTypes.bool,
    showSortedValues: PropTypes.bool,
    showTooltips: PropTypes.bool,
    sortDirection: PropTypes.string,
    startAngle: PropTypes.number,
    strokeColor: PropTypes.string,
    strokeWidth: PropTypes.number,
    subClass: PropTypes.string,
    tooltipType: PropTypes.string,
    width: PropTypes.number,
    xOffset: PropTypes.number,
    yOffset: PropTypes.number
};

TsdevPieChart.defaultProps = {
    id: `tsdev-pie-chart-${Date.now()}`,
    width: 250,
    height: 250,
    backgroundColor: 'transparent',
    backgroundColorLegend: 'transparent',
    dataSet: [
        {
            label: 'one',
            value: 10
        },
        {
            label: 'two',
            value: 40
        },
        {
            label: 'three',
            value: 20
        },
        {
            label: 'four',
            value: 20
        },
        {
            label: 'five',
            value: 10
        }
    ],
    xOffset: 0,
    yOffset: 0,
    colorRange: ['#85c7f1', '#549bf1', '#3329eb', '#0800a2', '#000000'],
    showSortedValues: false,
    sortDirection: 'asc',
    startAngle: 0,
    endAngle: 360,
    radius: 120,
    showTooltips: false,
    showInnerLabels: false,
    innerLabelColor: '#ffffff',
    innerLabelSize: 12,
    showOuterLabels: false,
    outerLabelColor: '#000000',
    rotation: 0,
    strokeColor: '#ffffff',
    strokeWidth: 0.7,
    showLabelLine: false,
    labelLineColor: '#000000',
    labelLineWidth: 0.7,
    showLabelLineDot: false,
    outerLabelOffset: 5,
    outerLabelSize: 12,
    showLegend: false,
    legendHeight: 70,
    legendColor: '#000000',
    labelLineDotColor: '#000000',
    labelLineDotRadius: 2,
    onSegmentClick: noop,
    subClass: '',
    innerLabelType: 'value',
    decimals: 2,
    outerLabelType: 'label',
    tooltipType: 'labelValue'
};

TsdevPieChart.displayName = 'TsdevPieChart';
