import { mqtt5, iot } from 'aws-iot-device-sdk-v2';
console.log('Worker: Starting up');

let client = null;
let currentConnectionId = 1;

self.onmessage = function(event) {
    const { type, params, topic, message, stamp } = event.data;
    console.log(`Worker: Received message of type: ${type}`);

    switch (type) {
        case 'connect':
            connect(params, stamp);
            break;
        case 'disconnect':
            disconnect(stamp);
            break;
        case 'is_connected':
            isConnected();
            break;
        case 'clear_topics':
            // No action needed in the worker
            break;
        case 'subscribe':
            subscribe(topic, stamp);
            break;
        case 'unsubscribe':
            unsubscribe(topic, stamp);
            break;
        case 'send':
            send(topic, message);
            break;
    }
};

function connect(params, stamp) {
    console.log('Worker: Attempting to connect');
    const { apiMqttUrl, apiMqttClientId, region, accessKeyId, secretAccessKey, sessionToken } = params;

    const configBuilder = iot.AwsIotMqtt5ClientConfigBuilder.new_with_websockets();

    configBuilder.with_clean_session(true);
    configBuilder.with_client_id(apiMqttClientId);
    configBuilder.with_endpoint(apiMqttUrl);
    configBuilder.with_credentials(region, accessKeyId, secretAccessKey, sessionToken);
    configBuilder.with_ping_timeout_ms(3000);
    configBuilder.with_connect_properties({
        keepAliveIntervalSeconds: 30,
        sessionExpiryIntervalSeconds: 300
    });

    const config = configBuilder.build();

    // MQTT5 uses a single client instance
    client = new mqtt5.Mqtt5Client(config);
    currentConnectionId++;

    setupConnectionListeners(currentConnectionId);

    client.start()
        .then(() => {
            console.log('Worker: Connection successful');
            self.postMessage({ type: 'connect_result', data: {success: true, connectionId: currentConnectionId, stamp} });
        })
        .catch((error) => {
            console.error('Worker: Connection failed', error);
            self.postMessage({ type: 'connect_result', data: {success: false, error: error.message, stamp} });
        });
}

function disconnect(stamp) {
    if (client) {
        const connectionId = currentConnectionId;
        client.stop()
            .then(() => {
                if(connectionId !== currentConnectionId) {
                    console.log('Worker: Connection Id mismatch, ignoring disconnect result', connectionId, currentConnectionId);
                    return;
                }
                self.postMessage({ type: 'disconnect_result', data: {success: true, stamp} });
            })
            .catch((error) => {
                if(connectionId !== currentConnectionId) {
                    console.log('Worker: Connection Id mismatch, ignoring disconnect result', connectionId, currentConnectionId);
                    return;
                }
                self.postMessage({ type: 'disconnect_result', data: { success: false, error: error.message, stamp} });
            });
        client = null;
    } else {
        self.postMessage({ type: 'disconnect_result', data: {success: true, stamp} });
    }
}

function isConnected() {
    const connected = client && client.getIsConnected();
    self.postMessage({ type: 'is_connected_result', data:{connected} });
}

function subscribe(topic, stamp) {
    if (client && client.getIsConnected()) {
        const subscription = {
            qos: mqtt5.QoS.AtLeastOnce,
            topicFilter: topic
        };

        client.subscribe(subscription)
            .then(() => {
                self.postMessage({ type: 'subscribe_result', data: {success: true, stamp} });
            })
            .catch((error) => {
                self.postMessage({ type: 'subscribe_result', data: {success: false, error: error.message, stamp} });
            });
    } else {
        self.postMessage({ type: 'subscribe_result', data: {success: false, error: 'Not connected', stamp} });
    }
}

function unsubscribe(topic, stamp) {
    if (client && client.getIsConnected()) {
        client.unsubscribe({ topicFilter: topic })
            .then(() => {
                self.postMessage({ type: 'unsubscribe_result', data: {success: true, stamp} });
            })
            .catch((error) => {
                self.postMessage({ type: 'unsubscribe_result', data: {success: false, error: error.message, stamp} });
            });
    } else {
        self.postMessage({ type: 'unsubscribe_result', data: {success: false, error: 'Not connected', stamp} });
    }
}

function send(topic, message) {
    if (client && client.getIsConnected()) {
        const publish = {
            qos: mqtt5.QoS.AtLeastOnce,
            topicName: topic,
            payload: message,
            retain: false
        };
        client.publish(publish);
    } else {
        console.error('Cannot send message: Not connected');
    }
}

function setupConnectionListeners(connectionId) {
    client.on('connectionSuccess', (eventData) => {
        if(connectionId !== currentConnectionId) {
            console.log('Worker: Connection Id mismatch, ignoring connectionSuccess event', connectionId, currentConnectionId);
            return;
        }
        self.postMessage({
            type: 'connection_success',
            data: {
                sessionPresent: eventData.sessionPresent,
                negotiatedSettings: eventData.negotiatedSettings
            },
            connectionId: connectionId
        });
    });

    client.on('connectionFailure', (error) => {
        if(connectionId !== currentConnectionId) {
            console.log('Worker: Connection Id mismatch, ignoring connectionFailure event', connectionId, currentConnectionId);
            return;
        }
        self.postMessage({ type: 'connection_failure', data: error, connectionId: connectionId });
    });

    client.on('disconnection', (eventData) => {
        if(connectionId !== currentConnectionId) {
            console.log('Worker: Connection Id mismatch, ignoring disconnect event', connectionId, currentConnectionId);
            return;
        }
        self.postMessage({
            type: 'disconnect',
            data: { reason: eventData.errorCode },
            connectionId: connectionId
        });
    });

    client.on('messageReceived', (eventData) => {
        if(connectionId !== currentConnectionId) {
            console.log('Worker: Connection Id mismatch, ignoring message event', connectionId, currentConnectionId);
            return;
        }
        self.postMessage({
            type: 'message',
            data: {
                topic: eventData.message.topicName,
                payload: eventData.message.payload,
                qos: eventData.message.qos,
                retain: eventData.message.retain,
                properties: eventData.message.properties
            },
            connectionId: connectionId
        });
    });

    client.on('error', (error) => {
        if(connectionId !== currentConnectionId) {
            console.log('Worker: Connection Id mismatch, ignoring error event', connectionId, currentConnectionId);
            return;
        }
        self.postMessage({ type: 'error', data: error });
    });
}

console.log('Worker: Setup complete');
