import { ref } from 'vue';

export const isConnected = ref(false);
export const profileConfig = ref(null);
export const latestCommandResult = ref(null);
export const isFirmwareOperationActive = ref(false);
export const firmwareProgress = ref({ operation: '', progress: 0 });

let ws = null;

// Subscribers for high-frequency events
const streamSubscribers = [];
const logSubscribers = [];
const ioSubscribers = [];

export function connectBackend() {
    const host = window.location.host;
    ws = new WebSocket(`ws://${host}/ws`);

    ws.onopen = () => {
        console.log('Connected to ESP Viewer Backend');
        isConnected.value = true;
    };

    ws.onclose = () => {
        console.log('Disconnected from ESP Viewer Backend');
        isConnected.value = false;
        profileConfig.value = null;
        // Auto reconnect
        setTimeout(connectBackend, 2000);
    };

    ws.onmessage = (event) => {
        try {
            const data = JSON.parse(event.data);
            handleEvent(data.event, data.payload);
        } catch (e) {
            console.error("Failed to parse message:", e);
        }
    };
}

export const chipInfo = ref(null);
export const partitionTable = ref(null);
export const appInfo = ref(null);
export const availablePorts = ref([]);
export const isDeviceConnected = ref(false);
export const isStreaming = ref(false);
export const latestFirmwareRead = ref(null);

function handleEvent(eventType, payload) {
    switch (eventType) {
        case 'PROFILE_LOADED':
            profileConfig.value = payload;
            break;
        case 'PROFILE_UPDATED':
            // Can be partial or full profile update
            if (payload.id === '__full_profile__') {
                try {
                    profileConfig.value = JSON.parse(payload.val);
                } catch (e) {
                    console.error("Failed to parse full profile update:", e);
                }
            } else {
                // Individual parameter update?
                // For now, most things use full profile sync, but we could update single params here.
            }
            break;
        case 'STREAM_DATA':
            streamSubscribers.forEach(cb => cb(payload));
            break;
        case 'STREAM_STATUS':
            isStreaming.value = payload.enabled;
            break;
        case 'LOG_MSG':
            logSubscribers.forEach(cb => cb(payload));
            break;
        case 'IO_DATA':
            ioSubscribers.forEach(cb => cb(payload));
            break;
        case 'CHIP_INFO_RECEIVED':
            chipInfo.value = payload;
            break;
        case 'PARTITION_TABLE_RECEIVED':
            partitionTable.value = payload;
            break;
        case 'APP_INFO_RECEIVED':
            appInfo.value = payload;
            break;
        case 'PORTS_LISTED':
            availablePorts.value = payload.ports || [];
            break;
        case 'STATUS_CHANGED':
            // E.g. device connected/disconnected
            isDeviceConnected.value = payload.connected;
            break;
        case 'ERROR':
            console.error("Backend Error:", payload.msg);
            alert(`Backend Error: ${payload.msg}`); // Simple fallback for user feedback
            break;
        case 'FIRMWARE_READ_COMPLETE':
            latestFirmwareRead.value = payload;
            firmwareProgress.value = { operation: '', progress: 0 };
            break;
        case 'FIRMWARE_PROGRESS':
            firmwareProgress.value = payload;
            break;
        default:
            console.log("Unhandled event:", eventType, payload);
    }
}

export function sendCommand(commandType, payload = {}) {
    if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({
            command: commandType,
            payload: payload
        }));
    } else {
        console.warn("Cannot send command, WebSocket not connected.");
    }
}

// Subscription APIs for components
export function subscribeToStream(callback) {
    streamSubscribers.push(callback);
}

export function subscribeToLogs(callback) {
    logSubscribers.push(callback);
}

export function subscribeToIO(callback) {
    ioSubscribers.push(callback);
}
