import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { Spacing } from "@uipath/apollo-core";
import { TimelinePauseIcon, TimelinePlayIcon, TimelineProgressIcon } from "../../../icons/index.js";
import { Column, Row } from "../../../layouts/index.js";
import { Button } from "@uipath/apollo-wind";
import { DateTime } from "luxon";
import react, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { calculateDurationMs, filterChildSpans, findAgentRunSpan, findAllAgentRunSpans, normalizeSpans, shouldRenderTimelinePlayer } from "./TimelinePlayer.utils.js";
const PERCENTAGE_MULTIPLIER = 100;
const SECONDS_PER_MINUTE = 60;
const MILLISECONDS_PER_SECOND = 1000;
const TIME_PADDING_DIGITS = 2;
const TIME_PADDING_CHAR = '0';
const SPAN_Z_INDEX_INACTIVE = 2;
const TIMELINE_BAR_HEIGHT = 30;
const TIMELINE_TRACK_BAR_HEIGHT = 4;
const TIMELINE_SPAN_HEIGHT = 5;
const SCRUBBER_SIZE = 10;
const SPEED_LEVEL_1 = 1;
const SPEED_LEVEL_2 = 2;
const SPEED_LEVEL_3 = 3;
const SPEED_LEVEL_4 = 5;
const TimelineBar = /*#__PURE__*/ react.forwardRef((props, ref)=>/*#__PURE__*/ jsx("div", {
        ref: ref,
        ...props,
        style: {
            position: 'relative',
            height: `${TIMELINE_BAR_HEIGHT}px`,
            flex: 1,
            cursor: 'pointer',
            ...props.style
        }
    }));
const SpanBlock = ({ left, width, isActive = false, isPlayed = false, depth = 0, title, status, progressPosition = 0 })=>{
    const [isHovered, setIsHovered] = useState(false);
    const getStatusColor = ()=>{
        if (1 === status) return 'var(--canvas-success-icon)';
        if (2 === status) return 'var(--canvas-error-icon)';
        if (3 === status) return 'var(--canvas-info-icon)';
        return 'var(--canvas-border-de-emp)';
    };
    const getBackgroundStyle = ()=>{
        if (isPlayed) return {
            backgroundColor: getStatusColor()
        };
        return {
            backgroundColor: 'var(--canvas-border-de-emp)'
        };
    };
    const getBaseBackgroundStyle = ()=>{
        const hasPartialElements = isActive && null !== getPartialElements();
        if (hasPartialElements) return {
            backgroundColor: 'transparent'
        };
        return getBackgroundStyle();
    };
    const getPartialElements = ()=>{
        if (!isActive || !status) return null;
        const spanStart = left;
        const spanEnd = left + width;
        if (progressPosition <= spanStart) return null;
        {
            if (progressPosition >= spanEnd) return null;
            const progressWithinSpan = (progressPosition - spanStart) / width * 100;
            return /*#__PURE__*/ jsxs(Fragment, {
                children: [
                    /*#__PURE__*/ jsx("div", {
                        style: {
                            position: 'absolute',
                            top: 0,
                            left: 0,
                            width: `${progressWithinSpan}%`,
                            height: '100%',
                            backgroundColor: 'var(--canvas-info-icon)',
                            borderRadius: 'var(--Small, 2px)',
                            borderTopRightRadius: 100 === progressWithinSpan ? 'var(--Small, 2px)' : 0,
                            borderBottomRightRadius: 100 === progressWithinSpan ? 'var(--Small, 2px)' : 0
                        }
                    }),
                    /*#__PURE__*/ jsx("div", {
                        style: {
                            position: 'absolute',
                            top: 0,
                            left: `${progressWithinSpan}%`,
                            width: `${100 - progressWithinSpan}%`,
                            height: '100%',
                            backgroundColor: 'var(--canvas-border-de-emp)',
                            borderRadius: 'var(--Small, 2px)',
                            borderTopLeftRadius: 0 === progressWithinSpan ? 'var(--Small, 2px)' : 0,
                            borderBottomLeftRadius: 0 === progressWithinSpan ? 'var(--Small, 2px)' : 0
                        }
                    })
                ]
            });
        }
    };
    return /*#__PURE__*/ jsx("div", {
        title: title,
        onMouseEnter: ()=>setIsHovered(true),
        onMouseLeave: ()=>setIsHovered(false),
        style: {
            position: 'absolute',
            top: `${(TIMELINE_BAR_HEIGHT - TIMELINE_SPAN_HEIGHT) / 2}px`,
            ...getBaseBackgroundStyle(),
            borderRadius: 'var(--Small, 2px)',
            left: `${left}%`,
            width: `${width}%`,
            height: `${TIMELINE_SPAN_HEIGHT}px`,
            boxShadow: 'inset 0 0 0 0px rgba(0, 0, 0, 0.1)',
            zIndex: SPAN_Z_INDEX_INACTIVE + depth + (isActive ? 1 : 0) + (isHovered ? 2 : 0),
            transition: 'all 0.2s ease-in-out',
            transform: isActive || isHovered ? 'scaleY(1.1)' : 'scaleY(1)',
            cursor: 'pointer',
            overflow: 'hidden'
        },
        children: getPartialElements()
    });
};
const TrackBar = ()=>/*#__PURE__*/ jsx("div", {
        style: {
            position: 'absolute',
            top: `${TIMELINE_BAR_HEIGHT / 2 - TIMELINE_TRACK_BAR_HEIGHT / 2}px`,
            backgroundColor: 'var(--canvas-background)',
            height: `${TIMELINE_TRACK_BAR_HEIGHT}px`,
            borderRadius: '2px',
            width: '100%',
            zIndex: 0
        }
    });
const Scrubber = ({ left })=>/*#__PURE__*/ jsx("div", {
        style: {
            position: 'absolute',
            top: `${TIMELINE_BAR_HEIGHT / 2 - SCRUBBER_SIZE / 2}px`,
            left: `calc(${left}% - ${SCRUBBER_SIZE / 2}px)`,
            display: 'flex',
            zIndex: 100,
            cursor: 'ew-resize'
        },
        children: /*#__PURE__*/ jsx(TimelineProgressIcon, {
            w: 10,
            h: 10,
            color: "color-mix(in srgb, var(--canvas-info-icon) 85%, black)"
        })
    });
function formatTime(ms) {
    const totalSeconds = Math.floor(ms / MILLISECONDS_PER_SECOND);
    const minutes = Math.floor(totalSeconds / SECONDS_PER_MINUTE);
    const seconds = totalSeconds % SECONDS_PER_MINUTE;
    return `${minutes}:${seconds.toString().padStart(TIME_PADDING_DIGITS, TIME_PADDING_CHAR)}`;
}
const TimelinePlayer = ({ spans, enableTimelinePlayer = true })=>{
    const [playing, setPlaying] = useState(false);
    const [progress, setProgress] = useState(0);
    const [isDragging, setIsDragging] = useState(false);
    const [speedLevel, setSpeedLevel] = useState(SPEED_LEVEL_1);
    const requestRef = useRef(void 0);
    const timelineRef = useRef(null);
    const mountedRef = useRef(true);
    const parentSpan = useMemo(()=>findAgentRunSpan(spans), [
        spans
    ]);
    const agentSpans = useMemo(()=>findAllAgentRunSpans(spans), [
        spans
    ]);
    const filteredSpans = useMemo(()=>filterChildSpans(spans, agentSpans), [
        agentSpans,
        spans
    ]);
    const normalizedSpans = useMemo(()=>normalizeSpans(filteredSpans), [
        filteredSpans
    ]);
    useEffect(()=>()=>{
            mountedRef.current = false;
        }, []);
    const durationMs = useMemo(()=>calculateDurationMs(parentSpan), [
        parentSpan
    ]);
    useEffect(()=>{
        if (durationMs > 0) {
            const durationMinutes = durationMs / 60000;
            if (durationMinutes > 5) setSpeedLevel(SPEED_LEVEL_4);
            else if (durationMinutes > 3) setSpeedLevel(SPEED_LEVEL_3);
            else durationMinutes > 1 ? setSpeedLevel(SPEED_LEVEL_2) : setSpeedLevel(SPEED_LEVEL_1);
        }
    }, [
        durationMs
    ]);
    const currentTimeMs = useMemo(()=>progress * durationMs, [
        progress,
        durationMs
    ]);
    const currentTimeFormatted = useMemo(()=>formatTime(currentTimeMs), [
        currentTimeMs
    ]);
    const totalTimeFormatted = useMemo(()=>formatTime(durationMs), [
        durationMs
    ]);
    const spanTimes = useMemo(()=>filteredSpans.map((span)=>({
                id: span.Id,
                start: DateTime.fromISO(span.StartTime).toMillis(),
                end: DateTime.fromISO(span.EndTime).toMillis()
            })), [
        filteredSpans
    ]);
    const timelineInfo = useMemo(()=>{
        const validTimes = spanTimes.filter((t)=>t.start > 0 && t.end > 0);
        if (0 === validTimes.length) return {
            minStart: 0,
            maxEnd: 0,
            duration: 0
        };
        const minStart = Math.min(...validTimes.map((t)=>t.start));
        const maxEnd = Math.max(...validTimes.map((t)=>t.end));
        const duration = maxEnd - minStart;
        return {
            minStart,
            maxEnd,
            duration
        };
    }, [
        spanTimes
    ]);
    const activeSpanIds = useMemo(()=>{
        if (0 === timelineInfo.duration) return [];
        const currentAbsoluteTime = timelineInfo.minStart + progress * timelineInfo.duration;
        return spanTimes.filter((span)=>currentAbsoluteTime >= span.start && currentAbsoluteTime <= span.end).map((span)=>span.id);
    }, [
        progress,
        spanTimes,
        timelineInfo
    ]);
    const playedSpanIds = useMemo(()=>{
        if (0 === timelineInfo.duration) return [];
        const currentAbsoluteTime = timelineInfo.minStart + progress * timelineInfo.duration;
        return spanTimes.filter((span)=>currentAbsoluteTime > span.start).map((span)=>span.id);
    }, [
        progress,
        spanTimes,
        timelineInfo
    ]);
    const mostActiveSpan = useMemo(()=>{
        if (0 === activeSpanIds.length) return null;
        const activeSpans = normalizedSpans.filter((span)=>activeSpanIds.includes(span.Id));
        return activeSpans.reduce((deepest, current)=>current.depth > deepest.depth ? current : deepest);
    }, [
        activeSpanIds,
        normalizedSpans
    ]);
    const previousMostActiveSpanId = useRef(null);
    useEffect(()=>{
        if (!enableTimelinePlayer) return;
        const currentSpanId = mostActiveSpan?.Id || null;
        if (currentSpanId !== previousMostActiveSpanId.current) {
            const event = new CustomEvent('activeSpanChange', {
                detail: currentSpanId
            });
            window.dispatchEvent(event);
            previousMostActiveSpanId.current = currentSpanId;
        }
    }, [
        mostActiveSpan?.Id,
        enableTimelinePlayer
    ]);
    const handleTimelineClick = useCallback((event)=>{
        if (!timelineRef.current) return;
        const rect = timelineRef.current.getBoundingClientRect();
        const clickX = event.clientX - rect.left;
        const newProgress = Math.max(0, Math.min(1, clickX / rect.width));
        setProgress(newProgress);
    }, []);
    const handleMouseDown = useCallback((event)=>{
        setIsDragging(true);
        setPlaying(false);
        handleTimelineClick(event);
    }, [
        handleTimelineClick
    ]);
    const handleMouseMove = useCallback((event)=>{
        if (!isDragging || !timelineRef.current) return;
        const rect = timelineRef.current.getBoundingClientRect();
        const clickX = event.clientX - rect.left;
        const newProgress = Math.max(0, Math.min(1, clickX / rect.width));
        setProgress(newProgress);
    }, [
        isDragging
    ]);
    const handleMouseUp = useCallback(()=>{
        setIsDragging(false);
    }, []);
    useEffect(()=>{
        if (isDragging) {
            document.addEventListener('mousemove', handleMouseMove);
            document.addEventListener('mouseup', handleMouseUp);
            return ()=>{
                document.removeEventListener('mousemove', handleMouseMove);
                document.removeEventListener('mouseup', handleMouseUp);
            };
        }
    }, [
        isDragging,
        handleMouseMove,
        handleMouseUp
    ]);
    const lastFrameTimeRef = useRef(void 0);
    useEffect(()=>{
        if (!playing || isDragging) return;
        const step = (timestamp)=>{
            if (!lastFrameTimeRef.current) lastFrameTimeRef.current = timestamp;
            const deltaTime = timestamp - lastFrameTimeRef.current;
            lastFrameTimeRef.current = timestamp;
            const progressIncrement = deltaTime * speedLevel * 2 / durationMs;
            if (mountedRef.current) {
                setProgress((currentProgress)=>{
                    const newProgress = Math.min(currentProgress + progressIncrement, 1);
                    if (newProgress >= 1) {
                        setPlaying(false);
                        lastFrameTimeRef.current = void 0;
                        return 1;
                    }
                    return newProgress;
                });
                if (playing) requestRef.current = requestAnimationFrame(step);
            }
        };
        requestRef.current = requestAnimationFrame(step);
        return ()=>{
            if (requestRef.current) cancelAnimationFrame(requestRef.current);
        };
    }, [
        playing,
        durationMs,
        isDragging,
        speedLevel
    ]);
    useEffect(()=>{
        lastFrameTimeRef.current = void 0;
    }, [
        playing,
        speedLevel
    ]);
    useEffect(()=>{
        setProgress(0);
        setPlaying(false);
        setIsDragging(false);
        lastFrameTimeRef.current = void 0;
        if (requestRef.current) {
            cancelAnimationFrame(requestRef.current);
            requestRef.current = void 0;
        }
    }, [
        parentSpan?.Id
    ]);
    const handlePlayPause = useCallback(()=>{
        if (progress >= 1) {
            setProgress(0);
            setPlaying(true);
        } else setPlaying(!playing);
    }, [
        progress,
        playing
    ]);
    const handleSpeedChange = useCallback(()=>{
        setSpeedLevel((prevLevel)=>{
            if (prevLevel === SPEED_LEVEL_1) return SPEED_LEVEL_2;
            if (prevLevel === SPEED_LEVEL_2) return SPEED_LEVEL_3;
            if (prevLevel === SPEED_LEVEL_3) return SPEED_LEVEL_4;
            return SPEED_LEVEL_1;
        });
    }, []);
    if (!shouldRenderTimelinePlayer(enableTimelinePlayer, durationMs, normalizedSpans)) return null;
    return /*#__PURE__*/ jsxs(Column, {
        py: Spacing.SpacingXs,
        px: Spacing.SpacingS,
        gap: Spacing.SpacingXs,
        minW: 640,
        style: {
            backgroundColor: 'var(--canvas-background-secondary)',
            color: 'var(--canvas-foreground)',
            borderRadius: '8px',
            border: '1px solid var(--canvas-border-de-emp)'
        },
        children: [
            /*#__PURE__*/ jsxs(Row, {
                align: "center",
                gap: Spacing.SpacingXs,
                children: [
                    /*#__PURE__*/ jsx(Button, {
                        variant: "ghost",
                        size: "icon",
                        className: "h-10 w-10",
                        onClick: handlePlayPause,
                        children: playing ? /*#__PURE__*/ jsx(TimelinePauseIcon, {
                            w: 24,
                            h: 24,
                            color: "var(--canvas-icon-default)"
                        }) : /*#__PURE__*/ jsx(TimelinePlayIcon, {
                            w: 24,
                            h: 24,
                            color: "var(--canvas-icon-default)"
                        })
                    }),
                    /*#__PURE__*/ jsxs("span", {
                        children: [
                            currentTimeFormatted,
                            " / ",
                            totalTimeFormatted
                        ]
                    }),
                    /*#__PURE__*/ jsx("span", {
                        children: mostActiveSpan?.Name
                    }),
                    /*#__PURE__*/ jsx("div", {
                        style: {
                            flex: 1
                        }
                    }),
                    /*#__PURE__*/ jsx(Button, {
                        variant: "ghost",
                        size: "icon",
                        className: "h-10 w-10",
                        onClick: handleSpeedChange,
                        children: /*#__PURE__*/ jsxs("span", {
                            className: "text-xs font-bold",
                            children: [
                                speedLevel,
                                "x"
                            ]
                        })
                    })
                ]
            }),
            /*#__PURE__*/ jsx(Row, {
                align: "center",
                style: {
                    marginLeft: '15px'
                },
                children: /*#__PURE__*/ jsxs(TimelineBar, {
                    ref: timelineRef,
                    onClick: handleTimelineClick,
                    onMouseDown: handleMouseDown,
                    children: [
                        /*#__PURE__*/ jsx(TrackBar, {}),
                        normalizedSpans.map((span)=>/*#__PURE__*/ jsx(SpanBlock, {
                                left: span.normalizedStart * PERCENTAGE_MULTIPLIER,
                                width: span.normalizedDuration * PERCENTAGE_MULTIPLIER,
                                isActive: activeSpanIds.includes(span.Id),
                                isPlayed: playedSpanIds.includes(span.Id),
                                depth: span.depth,
                                status: span.Status,
                                progressPosition: progress * PERCENTAGE_MULTIPLIER,
                                title: `${span.Name} (${formatTime(DateTime.fromISO(span.EndTime).toMillis() - DateTime.fromISO(span.StartTime).toMillis())})`
                            }, span.Id)),
                        /*#__PURE__*/ jsx(Scrubber, {
                            left: progress * PERCENTAGE_MULTIPLIER
                        })
                    ]
                })
            })
        ]
    });
};
export { TimelinePlayer };
