import React, { useCallback, useEffect, useMemo, useState, } from "react";
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, AreaChart, Area, } from "recharts";
import { RangeStartAndEndDateTimeUtil, } from "../../../../Types/Time/RangeStartAndEndDateTime";
import API from "../../../Utils/API/API";
import URL from "../../../../Types/API/URL";
import HTTPErrorResponse from "../../../../Types/API/HTTPErrorResponse";
import { APP_API_URL } from "../../../Config";
import ModelAPI from "../../../Utils/ModelAPI/ModelAPI";
import ComponentLoader from "../../ComponentLoader/ComponentLoader";
import OneUptimeDate from "../../../../Types/Date";
const CHART_COLORS = [
    "#6366f1", // indigo
    "#ec4899", // pink
    "#10b981", // emerald
    "#f59e0b", // amber
    "#06b6d4", // cyan
    "#8b5cf6", // violet
    "#f43f5e", // rose
    "#14b8a6", // teal
    "#64748b", // slate
    "#84cc16", // lime
];
const CHART_COLORS_MUTED = [
    "rgba(99,102,241,0.15)",
    "rgba(236,72,153,0.15)",
    "rgba(16,185,129,0.15)",
    "rgba(245,158,11,0.15)",
    "rgba(6,182,212,0.15)",
    "rgba(139,92,246,0.15)",
    "rgba(244,63,94,0.15)",
    "rgba(20,184,166,0.15)",
    "rgba(100,116,139,0.15)",
    "rgba(132,204,22,0.15)",
];
const DIMENSION_OPTIONS = [
    { value: "severityText", label: "Severity" },
    { value: "primaryEntityId", label: "Service" },
    { value: "traceId", label: "Trace ID" },
    { value: "spanId", label: "Span ID" },
];
const TOP_LIST_LIMITS = [5, 10, 25, 50];
function pivotTimeseriesData(rows) {
    const map = new Map();
    const seriesKeysSet = new Set();
    for (const row of rows) {
        let pivotRow = map.get(row.time);
        if (!pivotRow) {
            pivotRow = { time: row.time };
            map.set(row.time, pivotRow);
        }
        const groupKey = Object.values(row.groupValues).join(" / ") || "count";
        seriesKeysSet.add(groupKey);
        pivotRow[groupKey] = (pivotRow[groupKey] || 0) + row.count;
    }
    return {
        pivotedData: Array.from(map.values()),
        seriesKeys: Array.from(seriesKeysSet),
    };
}
function formatTickTime(time) {
    const date = OneUptimeDate.fromString(time);
    if (isNaN(date.getTime())) {
        return time;
    }
    return date.toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit",
        hour12: false,
    });
}
function formatYAxisTick(value) {
    if (value >= 1000000) {
        return `${(value / 1000000).toFixed(1)}M`;
    }
    if (value >= 1000) {
        return `${(value / 1000).toFixed(value >= 10000 ? 0 : 1)}K`;
    }
    return value.toString();
}
function computeDefaultBucketSize(startTime, endTime) {
    const diffMs = endTime.getTime() - startTime.getTime();
    const diffMinutes = diffMs / (1000 * 60);
    if (diffMinutes <= 60) {
        return 1;
    }
    if (diffMinutes <= 360) {
        return 5;
    }
    if (diffMinutes <= 1440) {
        return 15;
    }
    if (diffMinutes <= 10080) {
        return 60;
    }
    if (diffMinutes <= 43200) {
        return 360;
    }
    return 1440;
}
const AnalyticsTooltip = (props) => {
    if (!props.active || !props.payload || props.payload.length === 0) {
        return null;
    }
    const entries = props.payload
        .filter((entry) => {
        return entry.value > 0;
    })
        .map((entry) => {
        return {
            key: entry.dataKey,
            value: entry.value,
            color: entry.color,
        };
    });
    if (entries.length === 0) {
        return null;
    }
    const total = entries.reduce((sum, e) => {
        return sum + e.value;
    }, 0);
    const formatTime = (label) => {
        if (!label) {
            return "";
        }
        const date = OneUptimeDate.fromString(label);
        if (isNaN(date.getTime())) {
            return label;
        }
        return date.toLocaleString([], {
            month: "short",
            day: "numeric",
            hour: "2-digit",
            minute: "2-digit",
            hour12: false,
        });
    };
    return (React.createElement("div", { className: "rounded-lg border border-gray-200/80 bg-white/95 px-3.5 py-2.5 shadow-lg backdrop-blur-sm" },
        React.createElement("p", { className: "mb-2 border-b border-gray-100 pb-2 font-mono text-[11px] font-medium text-gray-400" }, formatTime(props.label)),
        React.createElement("div", { className: "space-y-1" }, entries.map((entry) => {
            return (React.createElement("div", { key: entry.key, className: "flex items-center justify-between gap-8" },
                React.createElement("div", { className: "flex items-center gap-2" },
                    React.createElement("span", { className: "inline-block h-2.5 w-2.5 rounded-[3px]", style: { backgroundColor: entry.color } }),
                    React.createElement("span", { className: "text-xs text-gray-600" }, entry.key)),
                React.createElement("span", { className: "font-mono text-xs font-semibold tabular-nums text-gray-800" }, entry.value.toLocaleString())));
        })),
        entries.length > 1 && (React.createElement("div", { className: "mt-2 flex items-center justify-between border-t border-gray-100 pt-2" },
            React.createElement("span", { className: "text-[11px] font-medium text-gray-400" }, "Total"),
            React.createElement("span", { className: "font-mono text-xs font-bold tabular-nums text-gray-900" }, total.toLocaleString())))));
};
const LogsAnalyticsView = (props) => {
    const [chartType, setChartType] = useState("timeseries");
    const [aggregation, setAggregation] = useState("count");
    const [aggregationField, setAggregationField] = useState("");
    const [groupByFields, setGroupByFields] = useState([
        "severityText",
    ]);
    const [topListLimit, setTopListLimit] = useState(10);
    const [isLoading, setIsLoading] = useState(false);
    const [timeseriesData, setTimeseriesData] = useState([]);
    const [topListData, setTopListData] = useState([]);
    const [tableData, setTableData] = useState([]);
    const allDimensionOptions = useMemo(() => {
        const attributeOptions = props.logAttributes
            .filter((attr) => {
            return !DIMENSION_OPTIONS.some((opt) => {
                return opt.value === attr;
            });
        })
            .map((attr) => {
            return { value: attr, label: attr };
        });
        return [...DIMENSION_OPTIONS, ...attributeOptions];
    }, [props.logAttributes]);
    const fetchAnalytics = useCallback(async () => {
        try {
            setIsLoading(true);
            const dateRange = RangeStartAndEndDateTimeUtil.getStartAndEndDate(props.timeRange);
            const startTime = dateRange.startValue;
            const endTime = dateRange.endValue;
            const requestData = {
                chartType,
                aggregation,
                startTime: startTime.toISOString(),
                endTime: endTime.toISOString(),
                bucketSizeInMinutes: computeDefaultBucketSize(startTime, endTime),
            };
            if (groupByFields.length > 0 &&
                groupByFields[0] &&
                groupByFields[0].length > 0) {
                requestData["groupBy"] =
                    groupByFields.filter((f) => {
                        return f.length > 0;
                    });
            }
            if (aggregation === "unique" && aggregationField) {
                requestData["aggregationField"] =
                    aggregationField;
            }
            if (chartType === "toplist" || chartType === "table") {
                requestData["limit"] = topListLimit;
            }
            if (props.serviceIds) {
                requestData["serviceIds"] =
                    props.serviceIds;
            }
            // Apply facet filters
            const severityValues = props.appliedFacetFilters.get("severityText");
            if (severityValues && severityValues.size > 0) {
                requestData["severityTexts"] =
                    Array.from(severityValues);
            }
            const serviceFilterValues = props.appliedFacetFilters.get("primaryEntityId");
            if (serviceFilterValues && serviceFilterValues.size > 0) {
                requestData["serviceIds"] =
                    Array.from(serviceFilterValues);
            }
            const traceFilterValues = props.appliedFacetFilters.get("traceId");
            if (traceFilterValues && traceFilterValues.size > 0) {
                requestData["traceIds"] =
                    Array.from(traceFilterValues);
            }
            const spanFilterValues = props.appliedFacetFilters.get("spanId");
            if (spanFilterValues && spanFilterValues.size > 0) {
                requestData["spanIds"] =
                    Array.from(spanFilterValues);
            }
            const response = await API.post({
                url: URL.fromString(APP_API_URL.toString()).addRoute("/telemetry/logs/analytics"),
                data: requestData,
                headers: Object.assign({}, ModelAPI.getCommonHeaders()),
            });
            if (response instanceof HTTPErrorResponse) {
                throw response;
            }
            const data = response.data["data"] || [];
            if (chartType === "timeseries") {
                setTimeseriesData(data);
            }
            else if (chartType === "toplist") {
                setTopListData(data);
            }
            else {
                setTableData(data);
            }
        }
        catch (_a) {
            // Silently degrade
            setTimeseriesData([]);
            setTopListData([]);
            setTableData([]);
        }
        finally {
            setIsLoading(false);
        }
    }, [
        chartType,
        aggregation,
        aggregationField,
        groupByFields,
        topListLimit,
        props.timeRange,
        props.serviceIds,
        props.appliedFacetFilters,
    ]);
    useEffect(() => {
        void fetchAnalytics();
    }, [fetchAnalytics]);
    const { pivotedData, seriesKeys } = useMemo(() => {
        return pivotTimeseriesData(timeseriesData);
    }, [timeseriesData]);
    const renderSelectControl = (label, value, onChange, options) => {
        return (React.createElement("div", { className: "flex items-center" },
            React.createElement("span", { className: "mr-2 text-[11px] font-medium uppercase tracking-wider text-gray-400" }, label),
            React.createElement("select", { className: "appearance-none rounded-md border border-gray-200 bg-white px-2.5 py-1.5 pr-7 text-xs font-medium text-gray-700 shadow-sm transition-all hover:border-gray-300 focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-100", value: value, onChange: (e) => {
                    onChange(e.target.value);
                }, style: {
                    backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")`,
                    backgroundRepeat: "no-repeat",
                    backgroundPosition: "right 6px center",
                } }, options.map((opt) => {
                return (React.createElement("option", { key: opt.value, value: opt.value }, opt.label));
            }))));
    };
    const renderQueryBuilder = () => {
        return (React.createElement("div", { className: "flex flex-wrap items-center gap-4 border-b border-gray-100 px-5 py-3" },
            renderSelectControl("Chart", chartType, (val) => {
                setChartType(val);
            }, [
                { value: "timeseries", label: "Timeseries" },
                { value: "toplist", label: "Top List" },
                { value: "table", label: "Table" },
            ]),
            React.createElement("div", { className: "h-4 w-px bg-gray-200" }),
            renderSelectControl("Measure", aggregation, (val) => {
                setAggregation(val);
            }, [
                { value: "count", label: "Count" },
                { value: "unique", label: "Unique Count" },
            ]),
            aggregation === "unique" && (React.createElement(React.Fragment, null, renderSelectControl("of", aggregationField, (val) => {
                setAggregationField(val);
            }, [{ value: "", label: "Select field..." }, ...allDimensionOptions]))),
            React.createElement("div", { className: "h-4 w-px bg-gray-200" }),
            renderSelectControl("Group by", groupByFields[0] || "", (val) => {
                setGroupByFields((prev) => {
                    const next = [...prev];
                    next[0] = val;
                    return next.filter((f) => {
                        return f.length > 0;
                    });
                });
            }, [{ value: "", label: "None" }, ...allDimensionOptions]),
            groupByFields[0] &&
                groupByFields[0].length > 0 &&
                renderSelectControl("then by", groupByFields[1] || "", (val) => {
                    setGroupByFields((prev) => {
                        const next = [prev[0] || ""];
                        if (val.length > 0) {
                            next.push(val);
                        }
                        return next.filter((f) => {
                            return f.length > 0;
                        });
                    });
                }, [
                    { value: "", label: "None" },
                    ...allDimensionOptions.filter((opt) => {
                        return opt.value !== groupByFields[0];
                    }),
                ]),
            (chartType === "toplist" || chartType === "table") && (React.createElement(React.Fragment, null,
                React.createElement("div", { className: "h-4 w-px bg-gray-200" }),
                renderSelectControl("Limit", topListLimit, (val) => {
                    setTopListLimit(Number(val));
                }, TOP_LIST_LIMITS.map((limit) => {
                    return { value: limit, label: String(limit) };
                }))))));
    };
    const renderLegend = () => {
        if (seriesKeys.length <= 1) {
            return React.createElement(React.Fragment, null);
        }
        return (React.createElement("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 px-5 pb-2" }, seriesKeys.map((key, index) => {
            return (React.createElement("div", { key: key, className: "flex items-center gap-1.5" },
                React.createElement("span", { className: "inline-block h-2.5 w-2.5 rounded-[3px]", style: {
                        backgroundColor: CHART_COLORS[index % CHART_COLORS.length],
                    } }),
                React.createElement("span", { className: "text-[11px] text-gray-500" }, key)));
        })));
    };
    const renderTimeseries = () => {
        if (pivotedData.length === 0) {
            return renderEmptyState();
        }
        const useAreaChart = seriesKeys.length === 1;
        return (React.createElement("div", { className: "px-2 pt-4 pb-2" },
            renderLegend(),
            React.createElement("div", { style: { height: 320 } },
                React.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, useAreaChart ? (React.createElement(AreaChart, { data: pivotedData, margin: { top: 8, right: 20, bottom: 4, left: 0 } },
                    React.createElement("defs", null,
                        React.createElement("linearGradient", { id: "areaGradient0", x1: "0", y1: "0", x2: "0", y2: "1" },
                            React.createElement("stop", { offset: "0%", stopColor: CHART_COLORS[0], stopOpacity: 0.2 }),
                            React.createElement("stop", { offset: "95%", stopColor: CHART_COLORS[0], stopOpacity: 0.02 }))),
                    React.createElement(CartesianGrid, { strokeDasharray: "none", stroke: "#f1f5f9", vertical: false }),
                    React.createElement(XAxis, { dataKey: "time", tickFormatter: formatTickTime, tick: { fontSize: 11, fill: "#94a3b8" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false, minTickGap: 50, interval: "preserveStartEnd", dy: 8 }),
                    React.createElement(YAxis, { tick: { fontSize: 11, fill: "#94a3b8" }, axisLine: false, tickLine: false, width: 52, allowDecimals: false, tickFormatter: formatYAxisTick }),
                    React.createElement(Tooltip, { content: React.createElement(AnalyticsTooltip, null), cursor: {
                            stroke: "#c7d2fe",
                            strokeWidth: 1,
                            strokeDasharray: "4 4",
                        } }),
                    React.createElement(Area, { dataKey: seriesKeys[0] || "count", stroke: CHART_COLORS[0], strokeWidth: 2, fill: "url(#areaGradient0)", dot: false, activeDot: {
                            r: 4,
                            fill: CHART_COLORS[0],
                            stroke: "#fff",
                            strokeWidth: 2,
                        }, isAnimationActive: false }))) : (React.createElement(BarChart, { data: pivotedData, margin: { top: 8, right: 20, bottom: 4, left: 0 }, barCategoryGap: "20%", barGap: 0 },
                    React.createElement(CartesianGrid, { strokeDasharray: "none", stroke: "#f1f5f9", vertical: false }),
                    React.createElement(XAxis, { dataKey: "time", tickFormatter: formatTickTime, tick: { fontSize: 11, fill: "#94a3b8" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false, minTickGap: 50, interval: "preserveStartEnd", dy: 8 }),
                    React.createElement(YAxis, { tick: { fontSize: 11, fill: "#94a3b8" }, axisLine: false, tickLine: false, width: 52, allowDecimals: false, tickFormatter: formatYAxisTick }),
                    React.createElement(Tooltip, { content: React.createElement(AnalyticsTooltip, null), cursor: { fill: "rgba(99,102,241,0.04)" } }),
                    seriesKeys.map((key, index) => {
                        return (React.createElement(Bar, { key: key, dataKey: key, stackId: "group", fill: CHART_COLORS[index % CHART_COLORS.length], radius: index === seriesKeys.length - 1
                                ? [3, 3, 0, 0]
                                : [0, 0, 0, 0], isAnimationActive: false, maxBarSize: 40 }));
                    })))))));
    };
    const renderTopList = () => {
        if (topListData.length === 0) {
            return renderEmptyState();
        }
        const maxCount = Math.max(...topListData.map((item) => {
            return item.count;
        }), 1);
        const totalCount = topListData.reduce((sum, item) => {
            return sum + item.count;
        }, 0);
        return (React.createElement("div", { className: "p-5" },
            React.createElement("div", { className: "space-y-1.5" }, topListData.map((item, index) => {
                const percentage = (item.count / maxCount) * 100;
                const sharePercent = totalCount > 0 ? Math.round((item.count / totalCount) * 100) : 0;
                const color = CHART_COLORS[index % CHART_COLORS.length] || CHART_COLORS[0];
                const mutedColor = CHART_COLORS_MUTED[index % CHART_COLORS_MUTED.length] ||
                    CHART_COLORS_MUTED[0];
                return (React.createElement("div", { key: index, className: "group flex items-center gap-3 rounded-lg px-3 py-2 transition-colors hover:bg-gray-50/80" },
                    React.createElement("span", { className: "w-5 text-right font-mono text-[11px] font-medium text-gray-300" }, index + 1),
                    React.createElement("div", { className: "h-2 w-2 rounded-full flex-shrink-0", style: { backgroundColor: color } }),
                    React.createElement("div", { className: "w-44 min-w-0 truncate text-sm font-medium text-gray-700" }, item.value || "(empty)"),
                    React.createElement("div", { className: "flex-1" },
                        React.createElement("div", { className: "relative h-7 w-full overflow-hidden rounded-md bg-gray-50" },
                            React.createElement("div", { className: "absolute left-0 top-0 h-full rounded-md transition-all duration-300", style: {
                                    width: `${percentage}%`,
                                    backgroundColor: mutedColor,
                                    borderLeft: `3px solid ${color}`,
                                } }))),
                    React.createElement("div", { className: "flex items-center gap-3 flex-shrink-0" },
                        React.createElement("span", { className: "font-mono text-sm font-semibold tabular-nums text-gray-800" }, item.count.toLocaleString()),
                        React.createElement("span", { className: "w-10 text-right font-mono text-[11px] tabular-nums text-gray-400" },
                            sharePercent,
                            "%"))));
            }))));
    };
    const renderTable = () => {
        var _a;
        if (tableData.length === 0) {
            return renderEmptyState();
        }
        const groupKeys = Object.keys(((_a = tableData[0]) === null || _a === void 0 ? void 0 : _a.groupValues) || {});
        const maxCount = Math.max(...tableData.map((row) => {
            return row.count;
        }), 1);
        return (React.createElement("div", { className: "p-5" },
            React.createElement("div", { className: "overflow-hidden rounded-lg border border-gray-200/80" },
                React.createElement("table", { className: "min-w-full" },
                    React.createElement("thead", null,
                        React.createElement("tr", { className: "border-b border-gray-200/80 bg-gray-50/80" },
                            React.createElement("th", { className: "w-10 px-4 py-2.5 text-left text-[11px] font-semibold uppercase tracking-wider text-gray-400" }, "#"),
                            groupKeys.map((key) => {
                                return (React.createElement("th", { key: key, className: "px-4 py-2.5 text-left text-[11px] font-semibold uppercase tracking-wider text-gray-400" }, key));
                            }),
                            React.createElement("th", { className: "px-4 py-2.5 text-right text-[11px] font-semibold uppercase tracking-wider text-gray-400" }, "Count"),
                            React.createElement("th", { className: "w-48 px-4 py-2.5 text-[11px] font-semibold uppercase tracking-wider text-gray-400" }))),
                    React.createElement("tbody", null, tableData.map((row, index) => {
                        const barWidth = (row.count / maxCount) * 100;
                        const color = CHART_COLORS[index % CHART_COLORS.length] || CHART_COLORS[0];
                        const mutedColor = CHART_COLORS_MUTED[index % CHART_COLORS_MUTED.length] ||
                            CHART_COLORS_MUTED[0];
                        return (React.createElement("tr", { key: index, className: "border-b border-gray-100/80 transition-colors last:border-b-0 hover:bg-gray-50/50" },
                            React.createElement("td", { className: "px-4 py-2.5 font-mono text-[11px] text-gray-300" }, index + 1),
                            groupKeys.map((key) => {
                                return (React.createElement("td", { key: key, className: "whitespace-nowrap px-4 py-2.5 text-sm text-gray-700" }, row.groupValues[key] || "(empty)"));
                            }),
                            React.createElement("td", { className: "whitespace-nowrap px-4 py-2.5 text-right font-mono text-sm font-semibold tabular-nums text-gray-800" }, row.count.toLocaleString()),
                            React.createElement("td", { className: "px-4 py-2.5" },
                                React.createElement("div", { className: "h-5 w-full overflow-hidden rounded bg-gray-50" },
                                    React.createElement("div", { className: "h-full rounded transition-all duration-300", style: {
                                            width: `${barWidth}%`,
                                            backgroundColor: mutedColor,
                                            borderLeft: `2px solid ${color}`,
                                        } })))));
                    }))))));
    };
    const renderEmptyState = () => {
        return (React.createElement("div", { className: "flex h-72 flex-col items-center justify-center gap-3" },
            React.createElement("svg", { className: "h-10 w-10 text-gray-200", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5 },
                React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" })),
            React.createElement("p", { className: "text-sm text-gray-400" }, "No data available for the selected query")));
    };
    const renderChart = () => {
        if (isLoading) {
            return (React.createElement("div", { className: "flex h-72 items-center justify-center" },
                React.createElement(ComponentLoader, null)));
        }
        if (chartType === "timeseries") {
            return renderTimeseries();
        }
        if (chartType === "toplist") {
            return renderTopList();
        }
        return renderTable();
    };
    return (React.createElement("div", { className: "overflow-hidden rounded-lg border border-gray-200/80 bg-white shadow-sm" },
        renderQueryBuilder(),
        renderChart()));
};
export default LogsAnalyticsView;
//# sourceMappingURL=LogsAnalyticsView.js.map