import React, { FC } from 'react';
import { formatMessage } from '@orchard/frontend-localization';
import * as Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import { formatNumber } from 'src/utils/formatNumber';
import { Help } from '@orchard/frontend-react-components';
import { render } from 'react-dom';
import { renderToString } from 'react-dom/server';
import { StreamsBreakdownSourceOfStreams } from 'src/selectors/soundRecordingStreamsBreakdown';

export const CLASSNAME = 'SourceOfStreamsChart';
export const TEST_ID = CLASSNAME;

const DEFAULT_CHART_OPTIONS = () => ({
    chart: {
        type: 'bar',
        styledMode: true,
        marginRight: 55
    },
    title: { text: '' },
    credits: { enabled: false },
    legend: { enabled: false },
    plotOptions: {
        bar: {
            borderRadius: 2,
            minPointLength: 3,
            pointWidth: 14,
            dataLabels: {
                enabled: true,
                crop: false,
                overflow: 'none',
                allowOverlap: true
            }
        }
    },
    tooltip: {
        enabled: false
    },
    xAxis: {
        categories: [
            'collection',
            'active',
            'passive',
            'unknown'
        ],
        title: {
            text: null
        },
        tickPixelInterval: 20,
        labels: {
            useHTML: true,
            formatter(this: Highcharts.AxisLabelsFormatterContextObject) {
                const uniqueId = () => Math.random().toString(36).substring(2, 9);
                const id = `highcharts-formatter-${uniqueId()}`;

                const component = (
                    <span>
                        <Help id={this.value.toString()} message={formatMessage(`sourceOfStreams.tooltip.${this.value}`)} />
                        <span>{formatMessage(`sourceOfStreams.${this.value}`)}</span>
                    </span>
                );

                const removeEvent = Highcharts.addEvent(this.axis, 'afterRender', () => {
                    const el = document.getElementById(id);
                    if (el) {
                        // Render the component as an element with events handlers and so on.
                        render(component, el);
                        el.removeAttribute('id');
                    }
                    // Remove event listener so it doesn't fire again
                    removeEvent();
                });

                return renderToString(
                    <div id={id}>
                        { component }
                    </div>
                );
            }
        }
    },
    yAxis: {
        min: 0,
        title: {
            text: null
        },
        labels: {
            format: '{value}%',
        }
    }
});

export const hasValue = (series: StreamsBreakdownSourceOfStreams) => (
    [series.collection, series.active, series.passive].some(breakdown => breakdown.total !== 0)
);

export const hasAnyValue = (series: StreamsBreakdownSourceOfStreams[]) => (
    series.some(item => hasValue(item))
);

export const createChartOptions = (series: StreamsBreakdownSourceOfStreams[]) => ({
    ...DEFAULT_CHART_OPTIONS(),
    chart: {
        ...DEFAULT_CHART_OPTIONS().chart,
        height: 200 + (series.length * 50)
    },
    series: series.map(item => ({
        type: 'bar',
        data: [item.collection, item.active, item.passive, item.unknown].map(({ value, total }, i) => ({
            y: value,
            x: i,
            dataLabels: {
                formatter: hasValue(item)
                    ? function formatter(this: Highcharts.DataLabelsFormatterContextObject) {
                        return `${formatNumber(total)} ${formatMessage('comparison.streams')}`;
                    }
                    : function formatter(this: Highcharts.DataLabelsFormatterContextObject) {
                        return formatMessage('error.noData.message');
                    }
            }
        }))
    })),
    yAxis: {
        ...DEFAULT_CHART_OPTIONS().yAxis,
        max: hasAnyValue(series) ? null : 100
    }
}) as Highcharts.Options;

export interface Props {
    series: StreamsBreakdownSourceOfStreams[];
}

const SourceOfStreamsChart: FC<Props> = ({ series }) => {
    const chartOptions = createChartOptions(series);

    return (
        <div className={CLASSNAME} data-testid={TEST_ID}>
            <HighchartsReact highcharts={Highcharts} options={chartOptions} />
        </div>
    );
};

export default SourceOfStreamsChart;
