import * as Echarts from 'echarts';
import { isObject, merge } from 'lodash';
import elementResizeEvent from 'element-resize-event';
import { isPath, getResByPath, getDataType, parseJsonStr, } from './helper/utils';
import { COLORS_1_X } from './helper/color';
import chartThemes from './theme';
import chartConfigs from './config';
import { optmizeChart } from './helper/performance';
class Wecharts extends HTMLElement {
    constructor() {
        super();
        this.chartInstance = null;
        this.loadingNode = null;
        this.cacheOptions = null;
        this.attachShadow({ mode: 'open' });
    }
    connectedCallback() {
        this.renderDom();
        this.chartInit();
    }
    disconnectedCallback() {
        if (this.chartInstance) {
            this.chartInstance.clear();
            this.chartInstance = null;
        }
        const container = this.shadowRoot.getElementById('rEchartsContainer');
        if (container) {
            elementResizeEvent.unbind(container, this.onResize);
            Echarts.dispose(container);
            this.shadowRoot.innerHTML = '';
        }
    }
    clear() {
        this.cacheOptions = null;
    }
    static get observedAttributes() {
        return ['loading'];
    }
    attributeChangedCallback(name, oldValue, newValue) {
        if (name === 'loading') {
            this.setLoading(newValue);
        }
    }
    getProps(key) {
        return this.getAttribute(key);
    }
    setLoading(loading) {
        const loadingTrue = loading === 'true' || loading === '';
        if (this.loadingNode) {
            const loadingEle = this.shadowRoot.getElementById('rEchartsLoading');
            const isContainLoadingNode = this.shadowRoot.contains(loadingEle);
            if (loadingTrue) {
                const container = this.shadowRoot.getElementById('rEchartsContainer');
                container.before(this.loadingNode);
            }
            else if (isContainLoadingNode) {
                this.shadowRoot.removeChild(loadingEle);
            }
        }
        else if (this.chartInstance) {
            if (loadingTrue) {
                this.chartInstance.showLoading();
            }
            else {
                this.chartInstance.hideLoading();
            }
        }
    }
    onResize() {
        const event = new CustomEvent('resizeAfter');
        this.chartInstance.resize();
        this.dispatchEvent(event);
    }
    chartInit() {
        const container = this.shadowRoot.getElementById('rEchartsContainer');
        const theme = this.getProps('theme') || 'wtLight';
        if (container) {
            Object.keys(chartThemes).forEach((key) => {
                Echarts.registerTheme(key, chartThemes[key]);
            });
            this.chartInstance = Echarts.init(container, theme);
            const loadingProp = this.getProps('loading');
            this.setGraphData(null);
            this.setLoading(loadingProp);
            const event = new CustomEvent('chartAfter', {
                detail: this.chartInstance,
            });
            setTimeout(() => {
                this.dispatchEvent(event);
                if (this.cacheOptions) {
                    this.setOptions(this.cacheOptions);
                }
            });
            elementResizeEvent(container, this.onResize.bind(this));
        }
    }
    setChartEvents(arg) {
        const container = this.shadowRoot.getElementById('rEchartsContainer');
        if (container) {
            Object.entries(arg)
                .filter(([key, fn]) => /^[a-zA-Z]*$/.test(key) && typeof fn === 'function')
                .forEach(([key, fn]) => {
                const eventName = key.toLowerCase();
                this.chartInstance &&
                    this.chartInstance.on(eventName, (params) => {
                        fn.call(this, params, this.chartInstance);
                    });
            });
        }
    }
    getChartConfig(graphType) {
        return JSON.parse(JSON.stringify(chartConfigs[graphType] || {}));
    }
    getColor() {
        const colorStr = this.getProps('color');
        return (colorStr === null || colorStr === void 0 ? void 0 : colorStr.split(',')) || undefined;
    }
    getDimensionsData(dimension, data) {
        let dimensionRes = [dimension];
        let dataRes = data;
        const quotaStr = this.getProps('dataQuota');
        const dimensionObj = parseJsonStr(dimension);
        if (dimensionObj || isPath(dimension)) {
            let dimensionKey = '';
            let dimensionValue = [];
            if (dimensionObj) {
                const { key, value } = dimensionObj;
                if (isPath(key)) {
                    dimensionKey = getResByPath(data, key);
                }
                dimensionValue = getResByPath(data, value);
            }
            else {
                const pathArr = dimension.split('.');
                dimensionKey = pathArr[pathArr.length - 1];
                dimensionValue = getResByPath(data, dimension);
            }
            dataRes = {
                [dimensionKey]: dimensionValue,
            };
            const quotaObj = parseJsonStr(quotaStr || '');
            const quotaKeys = [];
            if (quotaObj) {
                quotaObj.forEach(({ key, value }) => {
                    if (isPath(key)) {
                        const quotaKey = getResByPath(data, key);
                        quotaKeys.push(quotaKey);
                        dataRes[quotaKey] = getResByPath(data, value);
                    }
                    else {
                        quotaKeys.push(key);
                        dataRes[key] = getResByPath(data, value);
                    }
                });
            }
            else if (quotaStr) {
                quotaStr.split(',').forEach((item) => {
                    if (isPath(item)) {
                        const pathArr = item.split('.');
                        const quotaKey = pathArr[pathArr.length - 1];
                        quotaKeys.push(quotaKey);
                        dataRes[quotaKey] = getResByPath(data, item);
                    }
                    else {
                        quotaKeys.push(item);
                        dataRes[item] = data[item];
                    }
                });
            }
            dimensionRes = [dimensionKey, ...quotaKeys];
        }
        else {
            const dataType = getDataType(data);
            if (quotaStr) {
                dimensionRes = [dimension, ...quotaStr.split(',')];
            }
            if (dataType === 'array-obj') {
                const quota = Object.keys(data[0]).filter((key) => key !== dimension);
                dimensionRes = [dimension, ...quota];
            }
            if (dataType === 'object') {
                const quota = Object.keys(data).filter((key) => key !== dimension);
                dimensionRes = [dimension, ...quota];
            }
        }
        return { dimensions: dimensionRes, data: dataRes };
    }
    getRadius(graphType) {
        const radius = this.getProps('radius');
        const configs = this.getChartConfig(graphType);
        const configSeries = configs === null || configs === void 0 ? void 0 : configs.series;
        let radiusVal = '60%';
        switch (graphType) {
            case 'pie':
                radiusVal = radius || configSeries.radius || '60%';
                break;
            case 'ring':
                radiusVal = radius
                    ? radius.split(',')
                    : configSeries.radius || ['40%', '60%'];
                break;
            case 'rose':
                if (radius) {
                    const res = radius.split(',');
                    radiusVal = res.length === 1 ? res[0] : res;
                }
                else {
                    radiusVal = configSeries.radius || ['5%', '60%'];
                }
                break;
            default:
                radiusVal = '60%';
        }
        return radiusVal;
    }
    getLegend(graphType) {
        const legendShow = this.getProps('showLegend');
        const legendPosition = this.getProps('legendPosition');
        const legendOrient = this.getProps('legendOrient');
        const configs = this.getChartConfig(graphType);
        const configLegend = configs === null || configs === void 0 ? void 0 : configs.legend;
        const legend = Object.assign({}, configLegend);
        if (legendShow === 'false') {
            legend.show = false;
        }
        else {
            legend.show = true;
            legend.orient = legendOrient || legend.orient || 'horizontal';
            if (legendPosition && ['right', 'left'].includes(legendPosition)) {
                if (legendPosition === 'right') {
                    legend.right = 0;
                }
                else {
                    legend.left = 0;
                }
            }
            else if (legend.orient === 'vertical') {
                legend.left = 0;
                legend.top = 'middle';
            }
            else {
                legend.left = legendPosition || legend.left;
                legend.top = 0;
            }
        }
        return legend;
    }
    getToolbox(graphType) {
        const toolboxShow = this.getProps('showToolbox');
        const toolboxVal = this.getProps('toolbox');
        const toolPosition = this.getProps('toolPosition');
        const toolOrient = this.getProps('toolOrient');
        const configs = this.getChartConfig(graphType);
        const configToolbox = configs === null || configs === void 0 ? void 0 : configs.toolbox;
        const toolbox = Object.assign({}, configToolbox);
        if (toolboxShow === 'false') {
            return {
                show: false,
            };
        }
        if (toolboxVal) {
            const feature = {};
            toolboxVal.split(',').forEach((t) => {
                if (!t.trim())
                    return;
                if (t === 'magicType') {
                    feature['magicType'] = {
                        type: ['line', 'bar', 'stack'],
                    };
                }
                else {
                    feature[t] = {};
                }
            });
            toolbox.show = true;
            toolbox.feature = feature;
            toolbox.orient = toolOrient || 'horizontal';
            toolbox.left = toolPosition || 'right';
        }
        return toolbox;
    }
    getTooltip(graphType) {
        const tooltipTrigger = this.getProps('tooltipTrigger');
        const configs = this.getChartConfig(graphType);
        const configTooltip = configs === null || configs === void 0 ? void 0 : configs.tooltip;
        const tooltip = Object.assign({}, configTooltip);
        if (tooltipTrigger) {
            tooltip.trigger = tooltipTrigger;
        }
        return tooltip;
    }
    getGrid(graphType, { legend, dataZoom }) {
        const configs = this.getChartConfig(graphType);
        const configGrid = (configs === null || configs === void 0 ? void 0 : configs.grid) || {};
        if (legend.orient === 'horizontal') {
            if (legend.left) {
                configGrid.top = 60 + legend.top;
            }
            else if (legend.bottom) {
                configGrid.bottom = 200;
            }
        }
        else if (legend.orient === 'vertical') {
            if (legend.top) {
                configGrid.left = '16%';
            }
            else if (legend.right) {
                configGrid.right = '16%';
            }
        }
        if (dataZoom) {
            configGrid.bottom = (configGrid.bottom || 20) + 30;
        }
        return configGrid;
    }
    getxAxis(graphType) {
        const hideXaxis = this.getProps('hideXaxis');
        const configs = this.getChartConfig(graphType);
        const configXAxis = (configs === null || configs === void 0 ? void 0 : configs.xAxis) || {};
        if (hideXaxis) {
            configXAxis.show = false;
        }
        return configXAxis;
    }
    getyAxis(graphType) {
        const hideYaxis = this.getProps('hideYaxis');
        const configs = this.getChartConfig(graphType);
        const configYAxis = (configs === null || configs === void 0 ? void 0 : configs.yAxis) || {};
        configYAxis.axisLabel = configYAxis.axisLabel || {};
        if (hideYaxis) {
            configYAxis.show = false;
        }
        else {
            const scaleMap = {
                BW: 1000000,
                tenY: 1000000000,
            };
            const scaleMapD = {
                BW: 'M',
                tenY: 'B',
            };
            configYAxis.axisLabel.formatter = (value) => {
                const keys = Object.keys(scaleMap);
                for (const key of keys) {
                    if (value >= scaleMap[key]) {
                        return `${value / scaleMap[key]} ${scaleMapD[key]}`;
                    }
                }
                return value;
            };
        }
        return configYAxis;
    }
    getSeriesConfig(graphType) {
        const showLabelLine = this.getProps('showLabelLine');
        const showSeriesLabel = this.getProps('showSeriesLabel');
        const seriesLabelPosition = (this.getProps('seriesLabelPosition') || 'outside').split(',');
        const showLabel = showSeriesLabel !== null && showSeriesLabel !== void 0 ? showSeriesLabel : graphType === 'pie';
        const sLabelLine = showLabelLine !== null && showLabelLine !== void 0 ? showLabelLine : graphType === 'pie';
        const res = {
            label: {
                show: showLabel,
                position: seriesLabelPosition.length > 1
                    ? seriesLabelPosition
                    : seriesLabelPosition[0],
            },
            radius: this.getRadius(graphType),
            labelLine: { show: sLabelLine },
        };
        return res;
    }
    getSeries(graphType, data, dataLength) {
        const configs = this.getChartConfig(graphType);
        const quotaStr = this.getProps('dataQuota');
        const seriesConfig = this.getSeriesConfig(graphType);
        const mergeSeries = merge((configs === null || configs === void 0 ? void 0 : configs.series) || {}, seriesConfig);
        if (quotaStr) {
            const quota = parseJsonStr(quotaStr)
                ? parseJsonStr(quotaStr)
                : quotaStr.split(',');
            return quota.map(() => mergeSeries);
        }
        let series = [];
        const dataType = getDataType(data);
        if (dataType === 'array-matrix') {
            series = data[0].slice(1).map(() => mergeSeries);
        }
        else if (dataType === 'array-obj') {
            series = Object.keys(data[0])
                .slice(1)
                .map(() => mergeSeries);
        }
        else if (typeof data === 'object') {
            series = Object.keys(data)
                .slice(1)
                .map(() => mergeSeries);
        }
        if (dataLength > 300) {
            series = series.map((s) => optmizeChart(s, dataLength));
        }
        return series;
    }
    setGraphData(data) {
        const graphType = this.getProps('type');
        if (this.chartInstance) {
            if (data && graphType) {
                const graphTitle = this.getProps('title');
                const graphSubTitle = this.getProps('subTitle');
                const titlePositionVal = this.getProps('titlePosition');
                const showDataZoomVal = this.getProps('showDataZoom');
                const [left, top] = (titlePositionVal === null || titlePositionVal === void 0 ? void 0 : titlePositionVal.split(',')) || ['center', 0];
                const dimension = this.getProps('dataDimension');
                const backgroundColor = this.getProps('backgroundColor');
                if (graphType) {
                    let dataLength = data.length;
                    if (Array.isArray(data)) {
                        dataLength = data.length;
                    }
                    else if (isObject(data)) {
                        dataLength = Object.values(data)[0].length;
                    }
                    const graphOptions = this.getChartConfig(graphType);
                    graphOptions.series = this.getSeries(graphType, data, dataLength);
                    if (dimension && graphOptions.dataset) {
                        const dimensionsRes = this.getDimensionsData(dimension, data);
                        graphOptions.dataset.dimensions = dimensionsRes.dimensions;
                        graphOptions.dataset.source = dimensionsRes.data;
                    }
                    else if (graphOptions.dataset) {
                        graphOptions.dataset.source = data;
                    }
                    if (showDataZoomVal === 'false') {
                        graphOptions.dataZoom = null;
                    }
                    else if (dataLength >= (Number(showDataZoomVal) || 50)) {
                        graphOptions.grid = Object.assign(Object.assign({}, graphOptions.grid), { bottom: 40 });
                    }
                    else {
                        graphOptions.dataZoom = null;
                    }
                    if (graphOptions.title) {
                        graphOptions.title.text = graphTitle;
                        graphOptions.title.subtext = graphSubTitle;
                        graphOptions.title.left = left;
                        graphOptions.title.top = top || 0;
                    }
                    graphOptions.legend = this.getLegend(graphType);
                    graphOptions.toolbox = this.getToolbox(graphType);
                    graphOptions.tooltip = this.getTooltip(graphType);
                    graphOptions.grid = this.getGrid(graphType, graphOptions);
                    graphOptions.xAxis = this.getxAxis(graphType);
                    graphOptions.yAxis = this.getyAxis(graphType);
                    const colors = this.getColor();
                    if (colors) {
                        graphOptions.color = colors;
                    }
                    if (backgroundColor) {
                        graphOptions.backgroundColor = backgroundColor;
                    }
                    this.chartInstance.setOption(graphOptions);
                    setTimeout(() => {
                        var _a;
                        (_a = this.chartInstance) === null || _a === void 0 ? void 0 : _a.resize();
                    }, 100);
                }
            }
            else {
                this.setNoDataGraph();
            }
        }
    }
    setOptions(options) {
        if (this.chartInstance) {
            const isShowNoData = this.getProps('showNoData');
            const mode = this.getProps('mode');
            const keepCache = this.getProps('keepCache');
            const isShowDataBool = isShowNoData === 'true' || isShowNoData === '';
            if (!mode || mode === 'default') {
                this.chartInstance.clear();
            }
            if (options && !isShowDataBool) {
                const defaultOptions = Object.assign({}, options);
                defaultOptions.color = defaultOptions.color || COLORS_1_X;
                this.chartInstance.setOption(defaultOptions);
                this.chartInstance.resize();
                setTimeout(() => {
                    var _a;
                    (_a = this.chartInstance) === null || _a === void 0 ? void 0 : _a.resize();
                }, 100);
                this.cacheOptions = keepCache === 'true' ? defaultOptions : null;
            }
            else {
                this.setNoDataGraph();
            }
        }
    }
    setNoDataGraph() {
        if (this.chartInstance) {
            const noDataTitle = this.getProps('noDataTitle');
            this.chartInstance.setOption(chartConfigs.noData(noDataTitle || ''));
            setTimeout(() => {
                var _a;
                (_a = this.chartInstance) === null || _a === void 0 ? void 0 : _a.resize();
            }, 100);
        }
    }
    renderDom() {
        const template = document.createElement('template');
        const children = Array.from(this.children);
        const hasCustomLoading = children.length &&
            children.some((child) => child.getAttribute('slot') === 'loading');
        if (hasCustomLoading) {
            const loadingTemplate = document.createElement('template');
            loadingTemplate.innerHTML = `
        <div class="w-echarts-loading" id="rEchartsLoading">
          <div class="w-echarts-loading-spin">
            <slot name="loading"></slot>
          </div>
        </div>
      `;
            this.loadingNode = loadingTemplate.content.cloneNode(true);
        }
        template.innerHTML = `
      <style>
        :host {
          display: block;
          position: relative;
          width: 100%;
          height: 100%;
        }

        .w-echarts {
          width: 100%;
          height: 100%;
        }

        .w-echarts-loading {
          box-sizing: border-box;
          position: absolute;
          top: 0;
          left: 0;
          z-index: 99;
          width: 100%;
          height: 100%;
          text-align: center;
          background-color: rgba(255, 255, 255, 0.6);
        }

        .w-echarts-loading-spin {
          position: absolute;
          top: 50%;
          left: 50%;
          z-index: 99;
          transform: translate(-50%, -50%);
          padding: 16px;
          color: rgba(0, 0, 0, 0.6);
        }
      </style>

      <div class="w-echarts" id="rEchartsContainer"></div>
    `;
        this.shadowRoot.append(template.content.cloneNode(true));
    }
}
export const defineWecharts = () => {
    if (customElements.get('w-echarts'))
        return;
    customElements.define('w-echarts', Wecharts);
};
export default Wecharts;
//# sourceMappingURL=index.js.map