"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DanmuOverlay = DanmuOverlay;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const react_native_1 = require("react-native");
const livestream_store_1 = require("../../livestream-store");
const ui_1 = require("../ui");
const danmu_message_1 = require("./danmu-message");
const math_1 = require("./math");
const use_danmu_lanes_1 = require("./use-danmu-lanes");
const DEFAULT_LANE_COUNT = 12;
const DEFAULT_OPACITY = 80;
const DEFAULT_SPEED = 1;
const DEFAULT_MAX_MESSAGES = 50;
const FONT_SIZE_PERCENTAGE = 0.7;
const MAX_PROCESSED_MESSAGES = 10;
// px from top of video where danmu won't appear (avoid overlapping with title)
const TOP_GAP = 20;
// px from bottom of video (avoid overlapping with controls)
const BOTTOM_GAP = 20;
function DanmuOverlay({ enabled = true, opacity = DEFAULT_OPACITY, speed = DEFAULT_SPEED, laneCount = DEFAULT_LANE_COUNT, maxMessages = DEFAULT_MAX_MESSAGES, }) {
    const chat = (0, livestream_store_1.useChat)();
    const segment = (0, livestream_store_1.useLivestreamStore)((x) => x.segment);
    const [containerWidth, setContainerWidth] = (0, react_1.useState)(0);
    const [containerHeight, setContainerHeight] = (0, react_1.useState)(0);
    const [activeDanmu, setActiveDanmu] = (0, react_1.useState)(new Map());
    const processedMessages = (0, react_1.useRef)(new Set());
    const mountTime = (0, react_1.useRef)(Date.now());
    const lastChatLength = (0, react_1.useRef)(0);
    const { assignLane, updateDanmuWidth, releaseLane, cleanup } = (0, use_danmu_lanes_1.useDanmuLanes)(laneCount, containerWidth);
    const handleLayout = (0, react_1.useCallback)((event) => {
        const { width, height } = event.nativeEvent.layout;
        setContainerWidth(width);
        setContainerHeight(height);
    }, []);
    const handleMessageComplete = (0, react_1.useCallback)((messageId) => {
        releaseLane(messageId);
        setActiveDanmu((prev) => {
            const next = new Map(prev);
            next.delete(messageId);
            return next;
        });
    }, [releaseLane]);
    const handleWidthMeasured = (0, react_1.useCallback)((messageId, width) => {
        updateDanmuWidth(messageId, width);
    }, [updateDanmuWidth]);
    (0, react_1.useEffect)(() => {
        if (!enabled || !chat || containerWidth === 0)
            return;
        // only check new messages since last render (chat is sorted newest first)
        const newMessageCount = chat.length - lastChatLength.current;
        if (newMessageCount <= 0)
            return;
        const messagesToCheck = chat.slice(0, newMessageCount);
        lastChatLength.current = chat.length;
        const newMessages = messagesToCheck.filter((msg) => {
            const hasProcessed = processedMessages.current.has(msg.uri);
            const isSystem = msg.author.did === "did:sys:system";
            const msgTime = new Date(msg.record.createdAt).getTime();
            const isAfterMount = msgTime >= mountTime.current;
            return !hasProcessed && !isSystem && isAfterMount;
        });
        if (newMessages.length === 0)
            return;
        const messagesToAdd = [];
        for (const message of newMessages.slice(0, maxMessages)) {
            // mark as processed FIRST to prevent duplicate processing if effect runs twice
            if (processedMessages.current.has(message.uri)) {
                continue;
            }
            processedMessages.current.add(message.uri);
            if (processedMessages.current.size > MAX_PROCESSED_MESSAGES) {
                const toRemove = Array.from(processedMessages.current).slice(0, processedMessages.current.size - MAX_PROCESSED_MESSAGES);
                toRemove.forEach((uri) => processedMessages.current.delete(uri));
            }
            const duration = (0, math_1.baseDuration)(message, math_1.MAX_DURATION, math_1.MIN_DURATION);
            if (__DEV__)
                console.log("[danmu] message", message.record.text, {
                    duration,
                    speed,
                });
            const lane = assignLane(message.uri, duration);
            if (lane !== null) {
                messagesToAdd.push({ message, lane });
            }
        }
        if (messagesToAdd.length > 0) {
            setActiveDanmu((prev) => {
                const next = new Map(prev);
                for (const danmu of messagesToAdd) {
                    next.set(danmu.message.uri, danmu);
                }
                return next;
            });
        }
    }, [chat, enabled, speed, maxMessages]);
    (0, react_1.useEffect)(() => {
        const interval = setInterval(() => {
            cleanup();
        }, 1000);
        return () => clearInterval(interval);
    }, [cleanup]);
    if (!enabled || containerWidth === 0 || containerHeight === 0) {
        return (0, jsx_runtime_1.jsx)(ui_1.View, { style: styles.container, onLayout: handleLayout });
    }
    // Calculate video bounds based on actual video dimensions from segment
    const segmentVideoWidth = segment?.video?.[0]?.width;
    const segmentVideoHeight = segment?.video?.[0]?.height;
    // Fall back to 16:9 if no segment dimensions available
    const videoAspectRatio = segmentVideoWidth && segmentVideoHeight
        ? segmentVideoWidth / segmentVideoHeight
        : 16 / 9;
    const containerAspectRatio = containerWidth / containerHeight;
    let videoWidth;
    let videoHeight;
    let videoTop;
    let videoLeft;
    if (containerAspectRatio > videoAspectRatio) {
        // Container is wider than video - letterbox on sides
        videoHeight = containerHeight;
        videoWidth = videoHeight * videoAspectRatio;
        videoTop = 0;
        videoLeft = (containerWidth - videoWidth) / 2;
        // Adjust for top/bottom gaps iff we don't have top letterboxing
        videoTop += TOP_GAP;
        videoHeight -= TOP_GAP + BOTTOM_GAP;
    }
    else {
        // Container is taller than video - letterbox on top/bottom
        videoWidth = containerWidth;
        videoHeight = videoWidth / videoAspectRatio;
        videoTop = (containerHeight - videoHeight) / 2;
        videoLeft = 0;
    }
    const laneHeight = videoHeight / laneCount;
    const fontSize = laneHeight * FONT_SIZE_PERCENTAGE;
    return ((0, jsx_runtime_1.jsx)(ui_1.View, { style: styles.container, onLayout: handleLayout, pointerEvents: "none", children: Array.from(activeDanmu.values()).map(({ message, lane }) => ((0, jsx_runtime_1.jsx)(danmu_message_1.DanmuMessage, { message: message, lane: lane, laneHeight: laneHeight, videoTop: videoTop, opacity: opacity, fontSize: fontSize, speed: speed, containerWidth: containerWidth, containerHeight: containerHeight, onComplete: handleMessageComplete, onWidthMeasured: handleWidthMeasured }, message.uri))) }));
}
const styles = react_native_1.StyleSheet.create({
    container: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        overflow: "hidden",
    },
});
//# sourceMappingURL=danmu-overlay.js.map