import {useCallback, useEffect, useRef} from '@wordpress/element';
import {__} from '@wordpress/i18n';

// Audio
const audioStore = {
    // Audio element for notification sounds (reused for better performance)
    init: null,
    // Cache the audio URL to avoid recalculating it
    url: null,
};

// Global store for unseen messages count per chatbot UUID
const unseenMessagesCountStore = {};

// Global user interaction tracking
const userInteractionStore = {
    hasInteracted: false,
    listenersAttached: false,
    hasPendingSound: false, // Flag to indicate if sound should be played on user interaction
};

/**
 * Get unseen messages count for a chatbot UUID
 *
 * @param {string} chatbotUuid Chatbot UUID
 * @return {number} Unseen messages count
 */
export function getUnseenMessagesCount(chatbotUuid) {
    return unseenMessagesCountStore[chatbotUuid] || 0;
}

/**
 * Set unseen messages count for a chatbot UUID
 *
 * @param {string} chatbotUuid Chatbot UUID
 * @param {number} count Unseen messages count
 */
export function setUnseenMessagesCount(chatbotUuid, count) {
    unseenMessagesCountStore[chatbotUuid] = count;
    // Emit hook action to notify components of count change
    LimbChatbot?.Hooks?.doAction('lbaic.chatbot.unseenMessagesCount', chatbotUuid, count);
}

/**
 * Clear unseen messages count for a chatbot UUID
 *
 * @param {string} chatbotUuid Chatbot UUID
 */
export function clearUnseenMessagesCount(chatbotUuid) {
    setUnseenMessagesCount(chatbotUuid, 0);
}

/**
 * Reset document title to original if it was modified
 * This is useful when dismissing notifications manually
 */
export function resetDocumentTitle() {
    const currentTitle = document.title;
    const newMessageText = __('New message', 'limb-chatbot');
    // Check if title is modified with notification message
    if (currentTitle.includes(`${newMessageText} -`)) {
        // Extract original title
        const match = currentTitle.match(new RegExp(`\\(.+?\\) ${newMessageText} - (.+)`));
        if (match && match[1]) {
            document.title = match[1];
        }
    }
}

/**
 * Decrement document title count by specified amount
 * Updates the unseen messages count in the title, or resets to original if count reaches 0
 *
 * @param {string} chatbotUuid Chatbot UUID
 * @param {number} decrementBy Number of messages to decrement by
 */
export function decrementDocumentTitleCount(chatbotUuid, decrementBy = 1) {
    const currentTitle = document.title;
    const newMessageText = __('New message', 'limb-chatbot');

    // Check if title is modified with notification message
    if (currentTitle.includes(`${newMessageText} -`)) {
        // Extract current count and original title
        const match = currentTitle.match(new RegExp(`\\((\\d+)\\) ${newMessageText} - (.+)`));
        if (match && match[1] && match[2]) {
            const currentCount = parseInt(match[1], 10);
            const originalTitle = match[2];
            const newCount = Math.max(0, currentCount - decrementBy);

            if (newCount > 0) {
                // Update title with new count
                document.title = `(${newCount}) ${newMessageText} - ${originalTitle}`;
                // Update unseen messages count in store
                if (chatbotUuid) {
                    setUnseenMessagesCount(chatbotUuid, newCount);
                }
            } else {
                // Reset to original title
                document.title = originalTitle;
                // Clear unseen messages count
                if (chatbotUuid) {
                    clearUnseenMessagesCount(chatbotUuid);
                }
            }
        }
    }
}

/**
 * Actually play the sound (internal function)
 * This is the core logic that attempts to play the audio
 *
 * @return {Promise<void>}
 */
const executePlaySound = async () => {
    try {
        const audio = initAudio();

        // Set audio source if not already set or if it needs to be reset
        const audioUrl = getAudioUrl();
        if (!audio.src || audio.src !== audioUrl) {
            audio.src = audioUrl;
        }

        // Reset audio to beginning and play
        audio.currentTime = 0;
        await audio.play();
    } catch (e) {
        // Silently fail if audio is not available or blocked
        // This is expected in some browsers due to autoplay policies
        console.debug('Could not play notification sound:', e);
    }
}

/**
 * Initialize user interaction listeners
 * Sets up global event listeners to detect when user has interacted with the page
 * This is needed for browsers that block autoplay until user interaction
 */
const initUserInteractionTracking = () => {
    if (userInteractionStore.listenersAttached) {
        return;
    }

    const handleInteraction = () => {
        if (userInteractionStore.hasInteracted) {
            return; // Already detected
        }

        userInteractionStore.hasInteracted = true;

        // If there was a pending sound (from before interaction), play it once now
        if (userInteractionStore.hasPendingSound) {
            userInteractionStore.hasPendingSound = false;
            executePlaySound();
        }

        // Emit hook action to notify components of interaction
        LimbChatbot?.Hooks?.doAction('lbaic.chatbot.userInteracted');
    };

    // Listen for common interaction events (once per event type)
    window.addEventListener('click', handleInteraction, {once: true, passive: true});
    window.addEventListener('keydown', handleInteraction, {once: true, passive: true});
    window.addEventListener('touchstart', handleInteraction, {once: true, passive: true});
    // Also listen to mousedown for better coverage
    window.addEventListener('mousedown', handleInteraction, {once: true, passive: true});

    userInteractionStore.listenersAttached = true;
}

/**
 * Check if user has interacted with the document
 * Initializes interaction tracking if not already done
 *
 * @return {boolean} Whether user has interacted
 */
const hasUserInteracted = () => {
    // Initialize tracking on first check
    if (!userInteractionStore.listenersAttached) {
        initUserInteractionTracking();
    }

    return userInteractionStore.hasInteracted;
}

/**
 * Initialize audio element
 */
const initAudio = () => {
    if (!audioStore.init) {
        const audio = new Audio();
        audio.preload = 'auto';
        audio.volume = 1; // Set volume to 100%
        audioStore.init = audio;
    }

    return audioStore.init;
}

/**
 * Get the audio file URL
 * Constructs the path relative to the plugin directory
 * Caches the result for performance
 */
const getAudioUrl = () => {
    // Return cached URL if available
    if (audioStore.url) {
        return audioStore.url;
    }

    // Try to find the plugin URL from script tags
    const scripts = document.getElementsByTagName('script');
    for (let i = 0; i < scripts.length; i++) {
        const src = scripts[i].src;
        if (src && src.includes('limb-chatbot') && (src.includes('lbaic-chatbot') || src.includes('dist/js'))) {
            // Extract base URL and construct audio path
            const distIndex = src.indexOf('/dist/');
            if (distIndex !== -1) {
                const baseUrl = src.substring(0, distIndex);
                audioStore.url = `${baseUrl}/dist/audio/chatbot/agent-message.mp3?ver=${LimbChatbot?.version || 1}`;
                return audioStore.url;
            }
        }
    }
    // Fallback: construct from WordPress plugin structure
    const origin = window.location.origin;
    const pathMatch = window.location.pathname.match(/\/wp-content\/plugins\/[^/]+/);
    if (pathMatch) {
        audioStore.url = `${origin}${pathMatch[0]}/dist/audio/chatbot/agent-message.mp3?ver=${LimbChatbot?.version || 1}`;
        return audioStore.url;
    }
    // Last fallback: assume standard WordPress plugin structure
    audioStore.url = `${origin}/wp-content/plugins/limb-chatbot/dist/audio/chatbot/agent-message.mp3?ver=${LimbChatbot?.version || 1}`;
    return audioStore.url;
}

/**
 * Play sound
 * If user has interacted, plays immediately.
 * If user hasn't interacted yet, sets a flag to play sound once when user first interacts.
 * (required by browser autoplay policies)
 * Note: If multiple sounds are requested before interaction, only one will play on interaction.
 *
 * @return {Promise<void>}
 */
export async function playSound() {
    // Check if user has interacted with the document
    // hasUserInteracted() will initialize tracking if not already done
    if (hasUserInteracted()) {
        // User has already interacted, play sound immediately
        await executePlaySound();
    } else {
        // User hasn't interacted yet, set flag to play sound once when they do
        // If flag is already set, we don't need to set it again (only one sound will play)
        userInteractionStore.hasPendingSound = true;
    }
}

/**
 * Hook for playing notification sounds and updating document title
 * Handles audio file playback and title updates when tab is hidden
 *
 * @param {string} chatbotUuid Chatbot UUID for tracking unseen messages
 * @param {boolean} soundEnabled Whether sound is enabled
 * @param {boolean} isOnChatScreen Whether user is currently on the chat screen (not home or history)
 * @return {Function} playNotificationSound function to play the sound and update title
 */
export default function useSoundNotification(chatbotUuid, soundEnabled, isOnChatScreen) {
    // Store original document title
    const originalTitleRef = useRef(null);
    // Track title update timeout
    const titleTimeoutRef = useRef(null);
    // Track the new message count
    const newMessageCountRef = useRef(0);
    // Use ref to track current soundEnabled value so hook always has latest value
    const isSoundEnabledRef = useRef(soundEnabled);
    // Use ref to track current isOnChatScreen value so hook always has latest value
    const isOnChatScreenRef = useRef(isOnChatScreen);

    // Initialize user interaction tracking on mount
    // This ensures listeners are set up early, even before any sound is attempted
    useEffect(() => {
        initUserInteractionTracking();
    }, []);

    useEffect(() => {
        isSoundEnabledRef.current = soundEnabled;
    }, [soundEnabled]);

    useEffect(() => {
        isOnChatScreenRef.current = isOnChatScreen;
    }, [isOnChatScreen]);

    /**
     * Check if the tab is hidden (user is in another tab)
     */
    const isTabHidden = useCallback(() => {
        return document.hidden || document.webkitHidden || document.msHidden || false;
    }, []);

    /**
     * Update document title with new message count
     * Should NOT update only when: tab is visible AND chatbot is open AND user is on chat screen
     * Otherwise always update
     */
    const updateDocumentTitle = useCallback((incrementCount) => {
        const tabIsVisible = !isTabHidden();
        // Skip if the tab is visible AND the chatbot is open AND user is on chat screen
        if (tabIsVisible && isOnChatScreenRef.current) {
            return;
        }

        const newMessageText = __('New message', 'limb-chatbot');

        // Store original title on first update
        if (!originalTitleRef.current) {
            const currentTitle = document.title;
            // Check if title is already modified (contains "New message")
            if (currentTitle.includes(`${newMessageText} -`)) {
                // Extract original title from modified title
                const match = currentTitle.match(new RegExp(`\\(.+?\\) ${newMessageText} - (.+)`));
                if (match && match[1]) {
                    originalTitleRef.current = match[1];
                    // Extract current count if exists
                    const countMatch = currentTitle.match(/\((\d+)\)/);
                    if (countMatch && countMatch[1]) {
                        newMessageCountRef.current = parseInt(countMatch[1], 10);
                    }
                } else {
                    originalTitleRef.current = currentTitle;
                }
            } else {
                originalTitleRef.current = currentTitle;
            }
        }

        // Increment new message count
        newMessageCountRef.current += incrementCount;

        // Clear any existing timeout
        if (titleTimeoutRef.current) {
            clearTimeout(titleTimeoutRef.current);
            titleTimeoutRef.current = null;
        }

        // Update title with new message count (translated)
        if (newMessageCountRef.current > 0) {
            document.title = `(${newMessageCountRef.current}) ${newMessageText} - ${originalTitleRef.current}`;
        } else {
            document.title = originalTitleRef.current;
        }
    }, [isTabHidden]);

    /**
     * Restore original title
     * Only restore when tab becomes visible AND chatbot is open AND user is on chat screen
     */
    const restoreOriginalTitle = useCallback(() => {
        // Only restore if tab is visible AND user is on chat screen
        if (!isTabHidden() && isOnChatScreenRef.current && originalTitleRef.current) {
            document.title = originalTitleRef.current;
            // Clear timeout if exists
            if (titleTimeoutRef.current) {
                clearTimeout(titleTimeoutRef.current);
                titleTimeoutRef.current = null;
            }
            // Reset count
            newMessageCountRef.current = 0;
            // Clear unseen messages count
            if (chatbotUuid) {
                clearUnseenMessagesCount(chatbotUuid);
            }
        }
    }, [chatbotUuid]);

    /**
     * Reset document title when tab becomes visible
     */
    useEffect(() => {
        const handleVisibilityChange = () => {
            if (!isTabHidden()) {
                // Tab is now visible, restore original title immediately
                restoreOriginalTitle();
            }
        };

        document.addEventListener('visibilitychange', handleVisibilityChange);
        // Also listen for focus event as fallback
        window.addEventListener('focus', handleVisibilityChange);

        return () => {
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            window.removeEventListener('focus', handleVisibilityChange);
            // Cleanup timeout on unmount
            if (titleTimeoutRef.current) {
                clearTimeout(titleTimeoutRef.current);
            }
            // Restore title on unmount
            restoreOriginalTitle();
        };
    }, [restoreOriginalTitle]);

    /**
     * Restore document title when navigating to chat screen (if tab is visible)
     * Note: When using ref, this only runs when isOnChatScreen changes (not when ref.current changes)
     * But restoreOriginalTitle already reads from ref.current, so it will work correctly
     */
    useEffect(() => {
        if (isOnChatScreen && !isTabHidden()) {
            restoreOriginalTitle();
        }
    }, [isOnChatScreen, restoreOriginalTitle]);

    /**
     * Update unseen messages count in global store
     * Should NOT increment only when: tab is visible AND chatbot is open AND user is on chat screen
     * Otherwise always increment
     */
    const updateUnseenMessagesCount = useCallback((incrementCount) => {
        if (chatbotUuid) {
            const tabIsVisible = !isTabHidden();
            // Skip if tab is visible AND chatbot is open AND user is on chat screen
            if (tabIsVisible && isOnChatScreenRef.current) {
                return;
            }
            // Otherwise increment
            const currentCount = unseenMessagesCountStore[chatbotUuid] || 0;
            setUnseenMessagesCount(chatbotUuid, currentCount + incrementCount);
        }
    }, [chatbotUuid]);

    /**
     * Play notification sound and update document title
     * Should NOT play/update only when: tab is visible AND chatbot is open AND user is on chat screen
     * Otherwise always play/update
     * Handles browser autoplay policies
     */
    return useCallback(async (incrementCount = 1) => {
        // Check if sound is enabled
        if (!isSoundEnabledRef.current) {
            return;
        }

        const tabIsVisible = !isTabHidden();
        // Skip if tab is visible AND chatbot is open AND user is on chat screen
        if (tabIsVisible && isOnChatScreenRef.current) {
            return;
        }

        // Update document title (checks conditions internally)
        updateDocumentTitle(incrementCount);

        // Update unseen messages count (checks conditions internally)
        updateUnseenMessagesCount(incrementCount);

        if (incrementCount > 0) {
            playSound();
        }
    }, [isTabHidden, updateDocumentTitle, updateUnseenMessagesCount]);
}
