const { Client, DefaultMediaReceiver } = require('castv2-client');
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    terminal: false
});

let activeClient = null;
let activePlayer = null;

function isNotAllowedError(err) {
    if (!err) return false;
    const msg = (err.message || String(err)).toUpperCase();
    return msg.includes('NOT_ALLOWED') || msg.includes('NOT ALLOWED');
}

function stopSessions(client, sessions, cb) {
    if (!client || !sessions || sessions.length === 0) return cb();

    const remaining = sessions.slice();
    const stopNext = () => {
        const session = remaining.shift();
        if (!session) return cb();

        client.stop(session, (err) => {
            if (err) {
                log(`Stop session failed (${session.appId || 'unknown app'}): ${err.message || String(err)}`);
            } else {
                log(`Stopped session (${session.appId || 'unknown app'})`);
            }
            // Continue regardless; best-effort.
            stopNext();
        });
    };

    stopNext();
}

function log(msg) {
    console.log(JSON.stringify({ type: 'log', message: msg }));
}

function error(msg) {
    console.error(JSON.stringify({ type: 'error', message: msg }));
}

rl.on('line', (line) => {
    try {
        const data = JSON.parse(line);
        const { command, args } = data;

        switch (command) {
            case 'play':
                play(args.ip, args.url);
                break;
            case 'stop':
                stop();
                break;
            case 'volume':
                setVolume(args.level);
                break;
            default:
                error(`Unknown command: ${command}`);
        }
    } catch (e) {
        error(`Failed to parse line: ${e.message}`);
    }
});

function play(ip, url) {
    if (activeClient) {
        try { activeClient.close(); } catch (e) { }
    }

    activeClient = new Client();

    activeClient.connect(ip, () => {
        log(`Connected to ${ip}`);

        // First, check if DefaultMediaReceiver is already running
        activeClient.getSessions((err, sessions) => {
            if (err) return error(`GetSessions error: ${err.message}`);

            // Log sessions for debugging (appId/sessionId if available)
            try {
                const sessInfo = sessions.map(s => ({ appId: s.appId, sessionId: s.sessionId, displayName: s.displayName }));
                log(`Sessions: ${JSON.stringify(sessInfo)}`);
            } catch (e) {
                log('Sessions: (unable to stringify)');
            }

            // DefaultMediaReceiver App ID is CC1AD845
            const session = sessions.find(s => s.appId === 'CC1AD845');

            if (session) {
                log('Session already running, joining...');
                activeClient.join(session, DefaultMediaReceiver, (err, player) => {
                    if (err) {
                        log('Join failed, attempting launch...');
                        log(`Join error: ${err && err.message ? err.message : String(err)}`);
                        // Join can fail if the session is stale; stop it and retry launch.
                        stopSessions(activeClient, [session], () => launchPlayer(url, /*didStopFirst*/ true));
                    } else {
                        activePlayer = player;
                        loadMedia(url);
                    }
                });
            } else {
                // If another app is running, stop it first to avoid NOT_ALLOWED.
                if (sessions.length > 0) {
                    log('Non-media session detected, stopping before launch...');
                    stopSessions(activeClient, sessions, () => launchPlayer(url, /*didStopFirst*/ true));
                } else {
                    launchPlayer(url, /*didStopFirst*/ false);
                }
            }
        });
    });

    activeClient.on('error', (err) => {
        error(`Client error: ${err.message}`);
        try { activeClient.close(); } catch (e) { }
        activeClient = null;
        activePlayer = null;
    });
}

function launchPlayer(url, didStopFirst) {
    if (!activeClient) return;

    activeClient.launch(DefaultMediaReceiver, (err, player) => {
        if (err) {
            const details = `Launch error: ${err && err.message ? err.message : String(err)}${err && err.code ? ` (code: ${err.code})` : ''}`;
            // If launch fails with NOT_ALLOWED, the device may be busy with another app/session.
            // Best-effort: stop existing sessions once, then retry launch.
            if (!didStopFirst && isNotAllowedError(err)) {
                log('Launch NOT_ALLOWED; attempting to stop existing sessions and retry...');
                activeClient.getSessions((sessErr, sessions) => {
                    if (sessErr) {
                        error(`${details} | GetSessions error: ${sessErr.message || String(sessErr)}`);
                        return;
                    }
                    stopSessions(activeClient, sessions, () => {
                        activeClient.launch(DefaultMediaReceiver, (retryErr, retryPlayer) => {
                            if (retryErr) {
                                const retryDetails = `Launch retry error: ${retryErr && retryErr.message ? retryErr.message : String(retryErr)}${retryErr && retryErr.code ? ` (code: ${retryErr.code})` : ''}`;
                                error(retryDetails);
                                try { error(`Launch retry error full: ${JSON.stringify(retryErr)}`); } catch (e) { /* ignore */ }
                                return;
                            }
                            activePlayer = retryPlayer;
                            loadMedia(url);
                        });
                    });
                });
                return;
            }

            error(details);
            try { error(`Launch error full: ${JSON.stringify(err)}`); } catch (e) { /* ignore */ }
            return;
        }
        activePlayer = player;
        loadMedia(url);
    });
}

function loadMedia(url) {
    if (!activePlayer) return;

    const media = {
        contentId: url,
        contentType: 'audio/mpeg',
        streamType: 'LIVE',
        metadata: {
            metadataType: 0,
            title: 'Radio 1'
        }
    };

    activePlayer.load(media, { autoplay: true }, (err, status) => {
        if (err) return error(`Load error: ${err.message}`);
        log('Media loaded, playing...');
    });

    activePlayer.on('status', (status) => {
        // Optional: track status
    });
}

function stop() {
    if (activePlayer) {
        try { activePlayer.stop(); } catch (e) { }
        log('Stopped playback');
    }
    if (activeClient) {
        try { activeClient.close(); } catch (e) { }
        activeClient = null;
        activePlayer = null;
    }
}

function setVolume(level) {
    if (activeClient && activePlayer) {
        activeClient.setVolume({ level }, (err, status) => {
            if (err) return error(`Volume error: ${err.message}`);
            log(`Volume set to ${level}`);
        });
    } else {
        log('Volume command ignored: Player not initialized');
    }
}

log('Sidecar initialized and waiting for commands');
