/**
 * Composable pour gérer le WebRenderer navigateur.
 *
 * Utilise PMOPlayer pour le controle remote.
 * S'enregistre via POST /api/webrenderer/register
 * Utilise polling HTTP pour les commands
 */

import { ref, onMounted, onUnmounted, readonly } from "vue";
import { PMOPlayer } from "@/services/PMOPlayer";

function generateUUID(): string {
    if (typeof crypto.randomUUID === "function") {
        return crypto.randomUUID();
    }
    const bytes = new Uint8Array(16);
    crypto.getRandomValues(bytes);
    bytes[6] = (bytes[6]! & 0x0f) | 0x40;
    bytes[8] = (bytes[8]! & 0x3f) | 0x80;
    const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
    return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}

const INSTANCE_ID_KEY = "pmomusic_webrenderer_instance_id";
const RENDERER_UDN_KEY = "pmomusic_webrenderer_udn";

// Load persisted UDN on module load
function loadPersistedUdn(): string | null {
    try {
        return sessionStorage.getItem(RENDERER_UDN_KEY);
    } catch {
        return null;
    }
}

function savePersistedUdn(udn: string) {
    try {
        sessionStorage.setItem(RENDERER_UDN_KEY, udn);
    } catch {
        // ignore storage errors
    }
}

// Module-level singleton for PMOPlayer to prevent duplicate instances
let globalPlayer: PMOPlayer | null = null;
let globalInstanceId: string | null = null;
let registering = false;

// Module-level reactive state shared across all composable invocations
const sharedConnected = ref(false);
const sharedStreamUrl = ref<string | null>(null);
const sharedRendererUdn = ref<string | null>(loadPersistedUdn());

function getOrCreateInstanceId(): string {
    try {
        let id = sessionStorage.getItem(INSTANCE_ID_KEY);
        if (!id) {
            id = generateUUID();
            sessionStorage.setItem(INSTANCE_ID_KEY, id);
        }
        return id;
    } catch {
        return generateUUID();
    }
}

export function useWebRenderer() {
    const connected = sharedConnected;
    const streamUrl = sharedStreamUrl;
    const rendererUdn = sharedRendererUdn;

    let player: PMOPlayer | null = null;
    let onConnectedCallback: (() => void) | null = null;

    async function register(): Promise<void> {
        // Allow re-registration if we have a stale player but no connection
        if (globalPlayer && !connected.value) {
            console.log('[WebRenderer] stale globalPlayer, clearing');
            globalPlayer = null;
        }
        
        if (globalPlayer) {
            player = globalPlayer;
            connected.value = true;
            console.log('[WebRenderer] reusing existing player');
            return;
        }

        if (registering) {
            console.log('[WebRenderer] already registering, waiting...');
            // Wait a bit and try once
            await new Promise(r => setTimeout(r, 1000));
            if (globalPlayer) {
                player = globalPlayer;
                connected.value = true;
                return;
            }
        }
        
        registering = true;

        let instanceId;
        try {
            instanceId = getOrCreateInstanceId();
        } catch (e) {
            console.error('[WebRenderer] failed to get instanceId:', e);
            registering = false;
            return;
        }
        
        console.log('[WebRenderer] registering with instanceId:', instanceId);

        try {
            const resp = await fetch("/api/webrenderer/register", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    instance_id: instanceId,
                    user_agent: navigator.userAgent,
                }),
            });

            if (!resp.ok) {
                console.error("[WebRenderer] register failed:", resp.status);
                return;
            }

            const data = await resp.json();
            streamUrl.value = data.stream_url;
            rendererUdn.value = data.udn;
            savePersistedUdn(data.udn);

            player = new PMOPlayer(instanceId);
            globalPlayer = player;
            globalInstanceId = instanceId;
            player.setDebug(true);

            player.on('play', () => console.log('[WebRenderer] playing'));
            player.on('pause', () => console.log('[WebRenderer] paused'));

            // Si le backend est déjà en lecture (reconnexion après reload), démarrer immédiatement
            if (data.should_play && data.stream_url) {
                console.log('[WebRenderer] backend already playing, starting stream');
                player.playStream(data.stream_url);
            }

            connected.value = true;
            onConnectedCallback?.();
            
            // Force refresh renderers list after registration
            // The SSE might miss the initial event
            setTimeout(() => {
                console.log('[WebRenderer] forcing renderers refresh');
                window.dispatchEvent(new CustomEvent('webrenderer-registered'));
            }, 500);
        } catch (e) {
            console.error("[WebRenderer] register error:", e);
        } finally {
            registering = false;
        }
    }

    async function unregister(): Promise<void> {
        // Only unregister if this is the global player - prevent duplicate unregister calls
        if (player !== globalPlayer || !player) {
            return;
        }
        
        const instanceId = globalInstanceId || getOrCreateInstanceId();
        
        // Clear global first to prevent other components from using it
        globalPlayer = null;
        globalInstanceId = null;
        
        try {
            await fetch(`/api/webrenderer/${instanceId}`, { method: "DELETE" });
        } catch {
            // Ignored
        }
        player?.destroy();
        player = null;
    }

    function setVolume(_v: number): void {
        // PMOPlayer doesn't control volume directly - handled by backend
    }

    function setMute(_m: boolean): void {
        // PMOPlayer doesn't control mute directly - handled by backend
    }

    const beforeUnloadHandler = () => void unregister();

    onMounted(() => {
        void register();
        window.addEventListener("beforeunload", beforeUnloadHandler);
    });

    onUnmounted(() => {
        void unregister();
        window.removeEventListener("beforeunload", beforeUnloadHandler);
    });

    return {
        connected: readonly(connected),
        streamUrl: readonly(streamUrl),
        rendererUdn: readonly(rendererUdn),
        onConnected(fn: () => void) {
            onConnectedCallback = fn;
        },
        setVolume,
        setMute,
    };
}