/**
 * Output Window Renderer
 * Receives state from the main mixer window via BroadcastChannel
 * and renders the mixed output independently at full resolution.
 * Now with audio passthrough and per-deck FX support.
 */

const canvas = document.getElementById('output-canvas');
const ctx = canvas.getContext('2d');
const statusEl = document.getElementById('status');

let state = null;
let connected = false;
let lastStateTime = 0;

const decks = {
    a: { video: document.createElement('video'), image: null, currentSrc: '', type: null },
    b: { video: document.createElement('video'), image: null, currentSrc: '', type: null },
};

// Configure video elements — audio enabled for output window
for (const id of ['a', 'b']) {
    const v = decks[id].video;
    v.playsInline = true;
    v.preload = 'auto';
    v.crossOrigin = 'anonymous';
    // Start muted, unmute once connected
    v.muted = true;
}

// Audio unmute on first user interaction (browser policy)
let audioUnlocked = false;
function unlockAudio() {
    if (audioUnlocked) return;
    audioUnlocked = true;
    for (const id of ['a', 'b']) {
        decks[id].video.muted = false;
    }
    document.removeEventListener('click', unlockAudio);
    document.removeEventListener('keydown', unlockAudio);
}
document.addEventListener('click', unlockAudio);
document.addEventListener('keydown', unlockAudio);

const channel = new BroadcastChannel('mixer-sync');
channel.onmessage = (e) => {
    state = e.data;
    lastStateTime = performance.now();

    if (!connected) {
        connected = true;
        statusEl.textContent = 'Connected — click to enable audio';
        statusEl.classList.add('connected');
        setTimeout(() => { statusEl.style.opacity = '0'; }, 4000);
    }

    syncDeck('a', state.deckA);
    syncDeck('b', state.deckB);
};

// Send heartbeat
setInterval(() => {
    channel.postMessage({ type: 'output-heartbeat' });
}, 1000);


function syncDeck(id, deckState) {
    if (!deckState) return;
    const d = decks[id];
    const mediaUrl = deckState.mediaUrl;

    if (!mediaUrl) return;

    if (mediaUrl !== d.currentSrc) {
        d.currentSrc = mediaUrl;
        d.type = deckState.mediaType;

        if (deckState.mediaType === 'video') {
            d.image = null;
            d.video.src = mediaUrl;
            if (deckState.playing) {
                d.video.play().catch(() => {});
            }
        } else {
            d.video.pause();
            d.video.removeAttribute('src');
            const img = new Image();
            img.crossOrigin = 'anonymous';
            img.onload = () => { d.image = img; };
            img.onerror = () => { d.image = null; };
            img.src = mediaUrl;
        }
    }

    if (deckState.mediaType === 'video') {
        if (deckState.playing && d.video.paused) {
            d.video.play().catch(() => {});
        } else if (!deckState.playing && !d.video.paused) {
            d.video.pause();
        }

        // Sync time if drifted > 0.5s
        if (deckState.currentTime !== undefined && d.video.duration) {
            const drift = Math.abs(d.video.currentTime - deckState.currentTime);
            if (drift > 0.5) {
                d.video.currentTime = deckState.currentTime;
            }
        }

        if (deckState.speed && d.video.playbackRate !== deckState.speed) {
            d.video.playbackRate = deckState.speed;
        }

        // Sync volume based on crossfader position
        if (state) {
            const cf = state.crossfade || 0;
            const vol = deckState.volume || 1;
            if (id === 'a') {
                d.video.volume = vol * (1 - cf);
            } else {
                d.video.volume = vol * cf;
            }
        }
    }
}


function getDrawable(id) {
    const d = decks[id];
    if (d.type === 'video' && d.video.readyState >= 2) return d.video;
    if (d.type === 'image' && d.image) return d.image;
    return null;
}


function drawFit(ctx, src, canvasW, canvasH) {
    const srcW = src.videoWidth || src.naturalWidth || src.width;
    const srcH = src.videoHeight || src.naturalHeight || src.height;
    if (!srcW || !srcH) return;
    const scale = Math.max(canvasW / srcW, canvasH / srcH);
    const drawW = srcW * scale;
    const drawH = srcH * scale;
    const x = (canvasW - drawW) / 2;
    const y = (canvasH - drawH) / 2;
    ctx.drawImage(src, x, y, drawW, drawH);
}


function render() {
    const dpr = window.devicePixelRatio || 1;
    const w = canvas.width = window.innerWidth * dpr;
    const h = canvas.height = window.innerHeight * dpr;

    ctx.clearRect(0, 0, w, h);
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, w, h);

    if (state) {
        const srcA = getDrawable('a');
        const srcB = getDrawable('b');
        const cf = state.crossfade || 0;

        // Apply master FX
        if (state.fx) {
            const fx = state.fx;
            ctx.filter = `brightness(${fx.brightness}%) contrast(${fx.contrast}%) saturate(${fx.saturate}%) hue-rotate(${fx.hue}deg)`;
        }

        const transId = state.transition || 'crossfade';
        const transition = window.TransitionRegistry.get(transId);

        transition.render(ctx, srcA, srcB, cf, w, h, drawFit);

        ctx.filter = 'none';
        ctx.globalAlpha = 1;
        ctx.globalCompositeOperation = 'source-over';
    }

    // Check for disconnect
    if (connected && performance.now() - lastStateTime > 3000) {
        connected = false;
        statusEl.textContent = 'Disconnected';
        statusEl.classList.remove('connected');
        statusEl.style.opacity = '1';
    }

    requestAnimationFrame(render);
}

// Auto-hide cursor
let cursorTimeout;
document.addEventListener('mousemove', () => {
    document.body.classList.add('show-cursor');
    clearTimeout(cursorTimeout);
    cursorTimeout = setTimeout(() => {
        document.body.classList.remove('show-cursor');
    }, 3000);
});

// Fullscreen on double-click
canvas.addEventListener('dblclick', () => {
    if (document.fullscreenElement) {
        document.exitFullscreen();
    } else {
        document.documentElement.requestFullscreen();
    }
});

render();
