<template>
    <div id="flameGraphContent" class="flame-graph-content" />
</template>

<script>
import resize from '@/components/Charts/mixins/resize'
import { getFlameData } from '@/api/trace'
export default {
    mixins: [resize],
    data() {
        return {
            chart: null,
            apis: require("../../../assets/apis.jpg"),
            apm: require("../../../assets/apm.jpg"),
        }
    },
    props: ['tractID'],
    mounted() {
        this.$nextTick(() => {
            this.initChart()
        })
    },
    beforeDestroy() {
        if (!this.chart) {
            return
        }
        this.chart.dispose()
        this.chart = null
    },
    methods: {
        async initChart() {
            this.chart = this.$echarts5.init(document.getElementById('flameGraphContent'))

            var option;

            this.chart.showLoading();
            let para = {
                'trace_id': this.tractID
            }
            const res = await getFlameData(para)
            if (res) {
                this.chart.hideLoading();
                const chartResdata = res.OPT_STATUS // OPT_STATUS这个对象就是根节点
                const levelOfOriginalJson = this.heightOfJson(chartResdata);
                let seriesData = this.setSeries(this.recursionJson(chartResdata))
                option = {
                    backgroundColor: {
                        type: 'linear',
                        x: 0,
                        y: 0,
                        x2: 0,
                        y2: 1,
                        colorStops: [
                            {
                                offset: 0.05,
                                color: '#eee'
                            },
                            {
                                offset: 0.95,
                                color: '#eeeeb0'
                            }
                        ]
                    },
                    tooltip: {
                        className: 'custom-tooltip-box',
                        formatter: (params) => {
                            let res = `${params.marker} ${params.value[3]
                                }<br/>${params.marker} 耗时: ${params.value[7]}<br/>${params.marker} 比例: ${+params.value[4].toFixed(2)}%<br/>`
                            for (const key in params.data.detail) {
                                res += `${params.marker} ${key}: ${params.data.detail[key] || '--'}<br/>`
                            }
                            res += `<div style='position:absolute;bottom:10px;right:10px;width:80px;height:80px;z-index: -1;backdrop-filter: blur(10px);background-image:url("${params.value[6] == 'apm' ? this.apm : this.apis}");background-size:cover;background-repeat:no-repeat;background-position: center;'></div>`
                            return res;
                        }
                    },
                    toolbox: {
                        feature: {
                            restore: {}
                        },
                        right: 20,
                        top: 10
                    },
                    xAxis: {
                        show: false
                    },
                    yAxis: {
                        show: false,
                        max: levelOfOriginalJson
                    },
                    series: [
                        ...seriesData
                    ],
                    color: ['#f2d643', '#eb8146', '#ffb248', '#d95850'], // 图例的颜色
                    legend: {
                        show: true,
                        // data: this.formatCategoryData(chartResdata),
                        data: ['apm', 'syscall', 'network', 'unknown']
                    }

                };
                this.chart.setOption(option);
                this.chart.on('click', (params) => {
                    const data = this.recursionJson(chartResdata, params.data.span_name);
                    const rootValue = data[0].value[2];
                    this.chart.setOption({
                        xAxis: { max: rootValue },
                        series: [{ data }]
                    });
                });
            }
        },
        setSeries(chartResdata) {
            const renderItem = (params, api) => {
                const level = api.value(0);
                const start = api.coord([api.value(1), level]);
                const end = api.coord([api.value(2), level]);
                const height = ((api.size && api.size([0, 1])) || [0, 20])[1];
                const width = end[0] - start[0];
                const ProcessName = '进程名称'
                const CollectionEquipment = '采集设备'
                const CollectionName = `  ${api.value(6) == 'syscall' ? ProcessName + ':' + api.value(5) || '' : (api.value(6) == 'network' ? CollectionEquipment + ':' + api.value(5) || '' : '')}`
                return {
                    type: 'rect',
                    transition: ['shape'],
                    shape: {
                        x: start[0],
                        y: start[1] - height / 2,
                        width,
                        height: height - 2 /* itemGap */,
                        r: 2
                    },
                    style: {
                        fill: api.visual('color')
                    },
                    emphasis: {
                        style: {
                            stroke: '#000'
                        }
                    },
                    textConfig: {
                        position: 'insideLeft'
                    },
                    textContent: {
                        style: {
                            text: `${api.value(3)}  耗时:${api.value(7)}ms${CollectionName}`,
                            fontFamily: 'Verdana',
                            fill: '#000',
                            width: width - 4,
                            overflow: 'truncate',
                            ellipsis: '..',
                            truncateMinChar: 1
                        },
                        emphasis: {
                            style: {
                                stroke: '#000',
                                lineWidth: 0.5
                            }
                        }
                    }
                };
            };
            let res = []
            chartResdata.forEach(item => {
                if (item) {
                    let obj = {
                        type: 'custom',
                        name: item?.value[6] || '',
                        renderItem,
                        encode: {
                            x: [0, 1, 2],
                            y: 0
                        },
                        data: [item]
                    }
                    res.push(obj)
                }

            })
            return res
        },
        filterJson(json, id) {
            if (id == null) {
                return json;
            }
            const recur = (item, id) => {
                if (item.id === id) {
                    return item;
                }
                for (const child of item.children || []) {
                    if (item.children.length > 0) {
                        const temp = recur(child, id);
                        if (temp) {
                            item.children = [temp];
                            item.value = temp.duration; // change the parents' values
                            return item;
                        }
                    }

                }
            };
            return recur(json, id) || json;
        },
        recursionJson(jsonObj, id) {
            const data = [];
            const ColorTypes = {
                root: '#8fd3e8',
                apm: '#f2d643',
                syscall: '#eb8146',
                network: '#ffb248',
                unknown: '#d95850'
            };
            const filteredJson = this.filterJson(structuredClone(jsonObj), id);
            const rootVal = filteredJson.duration;
            const recur = (item, start = 0, level = 0) => {
                if (item) {
                    const ProcessName = '进程名称'
                    const CollectionEquipment = '采集设备'
                    const collectionName = `${item.span_category == 'syscall' ? item.detail[ProcessName] || '' : (item.span_category == 'network' ? item.detail[CollectionEquipment] || '' : '')}`
                    const temp = {
                        name: item?.id,
                        value: [
                            level,
                            start,
                            start + item.duration,
                            item.span_name,
                            (item.duration / rootVal) * 100,
                            collectionName,
                            item.span_category,
                            item.duration
                        ],
                        detail: item.detail,
                        itemStyle: {
                            color: ColorTypes[item.span_category]
                        }
                    };
                    data.push(temp);
                }
                let prevStart = start;
                if (item) {
                    for (const child of item.children || []) {
                        recur(child, prevStart, level + 1);
                        prevStart = prevStart + child?.duration || 0;
                    }
                }

            };
            recur(filteredJson);
            return data;
        },
        formatCategoryData(jsonObj, id) {
            const data = [];
            const filteredJson = this.filterJson(structuredClone(jsonObj), id);
            const recur = (item) => {
                if (item !== null && item !== undefined && Object.keys(item).length > 0) {
                    data.push(item?.span_category);
                    for (const child of item.children || []) {
                        if (item.children.length > 0) {
                            recur(child);
                        }
                    }
                }

            };
            recur(filteredJson);
            return [...new Set(data)];
        },
        heightOfJson(json) {
            const recur = (item, level = 0) => {
                if ((item && item.children || []).length === 0) {
                    return level;
                }
                let maxLevel = level;
                for (const child of item.children) {
                    const tempLevel = recur(child, level + 1);
                    maxLevel = Math.max(maxLevel, tempLevel);
                }
                return maxLevel;
            };
            return recur(json);
        }
    }
}
</script>
<style lang='scss' scoped>
.flame-graph-content {
    width: 100%;
    height: calc(100vh - 200px);
}

::v-deep .custom-tooltip-box {
    background-color: rgba(0, 0, 0, 0.6) !important;
    color: white !important;
}
</style>