import { EventEnvelope, EventType, TaskEnterPayload, TaskFinishPayload } from "@/api_fsb";
import { formatSecondsVerbose, formatSource, formatStatus, truncate } from "@/lib/utils";
import { selectAllEvents, selectCurrentSpeed } from "@/models/grlEventsSlice";
import getUnicodeFlagIcon from 'country-flag-icons/unicode';
import { useEffect, useRef, useState } from "react";
import { useSelector } from "react-redux";

// ─── Config ───────────────────────────────────────────────────────────────────

const SPEED_EASING = 0.025;  // how quickly speed transitions (per frame)

interface EventItemProps {
    event: EventEnvelope;
}

const EventTaskEnter = ({ event }: EventItemProps) => {
    const payload = event.payload as TaskEnterPayload;

    return (
        <>
            <span className="px-2 text-lg">{getUnicodeFlagIcon(payload.country_iso)}</span>
            <p>
                {truncate(event.product_user_id!, 6, "*****")} Entered{" "}
                {formatSource(payload.source)}{" "}
                (#{truncate(payload.survey_id!, 5, "***")})
            </p>
        </>
    )
}

const EventTaskFinish = ({ event }: EventItemProps) => {
    const payload = event.payload as TaskFinishPayload;

    return (
        <>
            <span className="px-2 text-lg">{getUnicodeFlagIcon(event.payload.country_iso)}</span>
            <p>
                {truncate(event.product_user_id!, 6, "*****")}{" "}
                {formatStatus(payload.status)} {formatSource(payload.source)}{" "}
                (#{truncate(payload.survey_id!, 5, "***")}) in{" "}
                {formatSecondsVerbose(payload.duration_sec!)}
            </p>
        </>
    )
}

const EventUserCreated = ({ event }: EventItemProps) => {

    return (
        <>
            <span className="px-2 text-lg">{getUnicodeFlagIcon(event.payload.country_iso)}</span>
            <p>{truncate(event.product_user_id!, 6, "*****")} Created</p>
        </>
    )
}


const EventComponent = ({ event }: EventItemProps) => {

    const renderContent = () => {
        switch (event.event_type) {
            case EventType.TaskEnter:
                return <EventTaskEnter event={event} />
            case EventType.TaskFinish:
                return <EventTaskFinish event={event} />
            case EventType.UserCreated:
                return <EventUserCreated event={event} />
            default:
                return <><p>Unknown event</p></>
        }
    }

    return (
        <div key={event.event_uuid!}
            className="inline-flex items-center text-[10px]
            font-mono px-2">
            {renderContent()}

            {/* <span className="text-red-500 pl-5">◆</span> */}
        </div >
    )
}


// ─── Main Component ───────────────────────────────────────────────────────────
export default function NewsTicker() {
    // --- Redux ---
    const reduxItems = useSelector(selectAllEvents);
    const targetSpeedRedux = useSelector(selectCurrentSpeed); // px/sec

    // --- Scroll state (all refs — no re-renders from animation) ---
    const containerRef = useRef<HTMLDivElement | null>(null);  // The ticker band 
    const stripRef = useRef<HTMLDivElement | null>(null);  // Scrolling strip
    const translateX = useRef(0);
    const currentSpeed = useRef(targetSpeedRedux);
    const targetSpeed = useRef(targetSpeedRedux);

    // Only state and refs persist across renders, the rest are re-initialized,
    // that is why this isn't just a standard variable.
    // Request Animation Frame reference (stores the animation frame ID)
    const rafRef = useRef<number | null>(null);
    const lastTime = useRef<number | null>(null);

    // --- Item tracking ---
    // Track which IDs are already in the scroller to only append 
    // genuinely new ones.
    const seenUUIDs = useRef(new Set<string>());
    const pendingQueue = useRef<EventEnvelope[]>([]);
    const [scrollItems, setScrollItems] = useState<EventEnvelope[]>([]);

    // --- Sync Redux → pendingQueue (only new items) ---
    useEffect(() => {
        const newItems = reduxItems.filter((item) => !seenUUIDs.current.has(item.event_uuid!));
        if (newItems.length === 0) return;

        newItems.forEach(item => seenUUIDs.current.add(item.event_uuid!));
        pendingQueue.current.push(...newItems);
    }, [reduxItems]);

    // --- Sync target speed from Redux ---
    useEffect(() => {
        targetSpeed.current = targetSpeedRedux;
    }, [targetSpeedRedux]);

    // --- RAF loop ---
    useEffect(() => {
        // This timestamp is a "high-resolution timestamp" provided by 
        // the browser, which is more accurate for measuring frame intervals 
        // than Date.now()
        const loop = (timestamp: number) => {
            console.log("RAF loop, timestamp:", timestamp, lastTime.current);

            if (!lastTime.current) lastTime.current = timestamp;
            const delta = (timestamp - lastTime.current) / 1000;
            lastTime.current = timestamp;

            // Slow easement towards targetSpeed
            currentSpeed.current +=
                (targetSpeed.current - currentSpeed.current) * SPEED_EASING;

            // flush pending queue into React state
            if (pendingQueue.current.length > 0) {
                const incoming = pendingQueue.current.splice(0);
                setScrollItems((prev) => [...prev, ...incoming]);
            }

            // Advance strip, slides it over left by X pixels
            translateX.current -= currentSpeed.current * delta;
            if (stripRef.current) {
                stripRef.current.style.transform = `translateX(${translateX.current}px)`;
            }

            // prune items that have fully exited the left edge
            if (stripRef.current && containerRef.current) {
                const children = Array.from(stripRef.current.children);
                const containerLeft = containerRef.current.getBoundingClientRect().left;
                let pruneCount = 0;
                let removedWidth = 0;

                for (const child of children) {
                    const rect = child.getBoundingClientRect();
                    if (rect.right < containerLeft - 20) {
                        pruneCount++;
                        removedWidth += rect.width;
                    } else {
                        break;
                    }
                }

                if (pruneCount > 0) {
                    translateX.current += removedWidth;
                    setScrollItems((prev) => prev.slice(pruneCount));
                }
            }

            // Assign the next loop
            rafRef.current = requestAnimationFrame(loop);
        };

        rafRef.current = requestAnimationFrame(loop);
        return () => cancelAnimationFrame(rafRef.current!);
    }, []);

    return (
        <div style={{
            minHeight: "3vh", display: "flex", flexDirection: "column",
            justifyContent: "center", alignItems: "center", gap: "0"
        }}>

            {/* Ticker wrapper */}
            <div style={{ width: "100%", position: "relative" }}>

                {/* The ticker band */}
                <div
                    ref={containerRef}
                    style={{
                        overflow: "hidden",
                        padding: "0",
                        position: "relative",
                    }}
                >

                    {/* Scrolling strip */}
                    <div
                        ref={stripRef}
                        style={{
                            display: "inline-flex",
                            alignItems: "center",
                            whiteSpace: "nowrap",
                            padding: "10px 0",
                            willChange: "transform",
                            position: "relative",
                            zIndex: 2,
                        }}
                    >
                        {scrollItems.map(item => (
                            <EventComponent event={item} />
                        ))}

                        {/* Trailing spacer so new content doesn't immediately snap in */}
                        <span style={{ paddingRight: "100vw", display: "inline-block" }} />

                    </div>
                </div>

            </div>

        </div>
    );
}
