import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import * as d3 from 'd3';
import classnames from 'classnames';

const COLORS = {
    Green: '#5FB95C',
    Red: '#F95B5C',
    Black: '#2F2F2F',
    MediumGrey: '#C8CCD1',
    LightGrey: '#E2E6E9',
    White: '#FFFFFF',
    Orange: '#FF8800'
};

const VALUES = {
    BASIC_RADIUS_RATE: 2.4,
    ENTITY_WIDTH_RATE: 0.14,
    NO_CALL_OFFSET_RATE: 0.49,
    WARNING_TEXT_OFFSET_RATE: 0.37
};

export class DonutChart extends React.Component {
    static propTypes = {
        theme: PropTypes.object,
        percent: PropTypes.number,
        width: PropTypes.number,
        height: PropTypes.number,
        alignCenter: PropTypes.bool,
        thresholdValue: PropTypes.object,
        percentText: PropTypes.string,
        warningText: PropTypes.string,
        animation: PropTypes.bool,
        percentFontSize: PropTypes.number,
        testAutomationId: PropTypes.string,
        className: PropTypes.string
    };

    static defaultProps = {
        width: 220,
        height: 220,
        alignCenter: true,
        percent: 0,
        thresholdValue: {},
        percentText: null,
        warningText: null,
        theme: {
            CHART_GREEN: COLORS.Green,
            CHART_RED: COLORS.Red,
            CHART_ORANGE: COLORS.Orange
        },
        animation: true,
        percentFontSize: 40,
        testAutomationId: 'donutChart',
        className: null
    };

    constructor(props, context) {
        super(props, context);
        let radius = this.calculateRadius();
        let entityOuterRadius = radius * (1 + VALUES.ENTITY_WIDTH_RATE / 2);
        let entityInnerRadius = radius * (1 - VALUES.ENTITY_WIDTH_RATE / 2);

        this.state = {
            entityArc: d3
                .arc()
                .outerRadius(entityOuterRadius)
                .innerRadius(entityInnerRadius)
                .cornerRadius(15)
                .startAngle(0)
        };
    }

    componentDidMount() {
        this.drawProgressBarLine();
    }

    componentDidUpdate() {
        this.drawProgressBarLine();
    }

    drawProgressBarLine() {
        let {animation, percent} = this.props;
        let {entityPath} = this.refs;
        let endAngle = this.calculateEndAngle(percent);
        let entityColor = this.getEntityColor();
        let {entityArc} = this.state;

        if (animation) {
            d3
                .select(entityPath)
                .attr('fill', entityColor)
                .datum({endAngle})
                .attr('d', entityArc);
        } else {
            d3
                .select(entityPath)
                .attr('fill', entityColor)
                .attr('d', entityArc({endAngle}));
        }
    }

    calculateRadius() {
        return this.props.height / VALUES.BASIC_RADIUS_RATE;
    }

    calculateEndAngle(percent) {
        return 2 * Math.PI * percent;
    }

    getEntityColor() {
        let {percent, thresholdValue, theme} = this.props;
        let {upperLimit, lowerLimits} = thresholdValue;

        if (_.isEmpty(thresholdValue)) {
            return theme.CHART_GREEN;
        }

        if (percent < lowerLimits) {
            return theme.CHART_GREEN;
        }

        if (percent >= lowerLimits && percent < upperLimit) {
            return theme.CHART_ORANGE;
        }

        if (percent >= upperLimit) {
            return theme.CHART_RED;
        }
    }

    getPercent() {
        let {percent, percentText, percentFontSize} = this.props;
        let textConfig = {
            textAnchor: 'middle',
            y: 12,
            fill: COLORS.Black,
            style: {
                fontSize: percentFontSize + 'px'
            }
        };

        if (_.isNull(percentText)) {
            return (
                <text {...textConfig} data-test-automation-id="percent" id="percent">
                    <tspan>{parseInt(percent * 100)}</tspan>
                    <tspan>%</tspan>
                </text>
            );
        }
        return null;
    }

    getNoCall() {
        let {percentText, height} = this.props;
        let noCallStyle = {
            position: 'relative',
            bottom: `${height * VALUES.NO_CALL_OFFSET_RATE + 22}px`,
            color: COLORS.Black,
            fontSize: '20px',
            margin: '0 auto',
            width: '145px',
            wordWrap: 'break-word'
        };

        if (_.isNull(percentText)) {
            return null;
        }

        return (
            <div style={noCallStyle} data-test-automation-id="noCalls">
                {percentText}
            </div>
        );
    }

    getWarningText() {
        let {warningText, height} = this.props;

        let warningTextStyle = {
            position: 'relative',
            bottom: `${height * VALUES.WARNING_TEXT_OFFSET_RATE + 3}px`,
            fontSize: '13px',
            margin: '0 auto',
            width: '120px',
            wordWrap: 'break-word'
        };
        return (
            <div style={warningTextStyle} data-test-automation-id="warning">
                {warningText}
            </div>
        );
    }

    render() {
        let {width, height} = this.props;
        let containerStyle = {
            width: width + 'px',
            height: height + 'px'
        };
        let gTransform = 'translate(' + height / 2 + ',' + height / 2 + ')';
        let className = classnames(this.props.className);

        return (
            <div style={containerStyle} className={className}>
                <svg width={width} height={height} role="img" aria-labelledby="percent">
                    <g transform={gTransform}>
                        <circle
                            cx="0"
                            cy="0"
                            r={this.calculateRadius()}
                            stroke={COLORS.LightGrey}
                            fill="none"
                            strokeWidth="2"
                        />
                        <path ref="entityPath" />
                        {this.getPercent()}
                    </g>
                </svg>
                {this.getWarningText()}
                {this.getNoCall()}
            </div>
        );
    }
}
