<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';

export let log_lvl: number = 0;
export let ws_connect: boolean = false;
export let ws_connect_status: null|string = null;
export let ws_server = 'dev-api.oneskyit.com';
export let base_url = `wss://${ws_server}/ws`;
export let group_id = 'ae-grp-99';
export let client_id = Date.now();

export let cmd: null|string = null;
export let msg: null|string = null;
export let type: null|string = null; // msg, cmd, json, hello, bye
export let trigger_send: any = null;
export let classes: string = 'container p-1 bg-pink-100 text-xs mx-auto pb-16 mb-20 sm:mb-12 md:mb-8';
export let hide__ws_form: boolean = true;
export let hide__ws_messages: boolean = false;
export let hide__ws_commands: boolean = false;

// *** Set initial variables
const dispatch = createEventDispatcher();

// JSON formatted data
let ws_data = {
    'client_id': null, // The device or browser ID if available.
    // 'src': null, // Sending client
    // 'account_id': null, // Essentially the person ID or user ID if available.
    // 'dest': null, // Destination client
    'target': 'echo', // echo, dm (direct), grp (group), all (broadcast)
    'type': 'cmd', // msg, cmd, json, hello, bye
    // 'grp': null, // Destination group
    'msg': null, // Message string
    'cmd': null, // Command string
    // 'data': null,
    // 'b64': null,
}

let ws_received_list_cmd: string[] = [];
let ws_received_list_other: any[] = [];
let ws_received_list_msg: string[] = [];


onMount(async () => {
    console.log('** Component Mounted: ** Element Websocket v2');
});


function ws_connect_group_id({group_id, client_id}) {
    console.log(`${base_url}/group/${group_id}/client/${client_id}`);
    let ws_connection = new WebSocket(`${base_url}/group/${group_id}/client/${client_id}`);

    ws_connection.onopen = function() {
        console.log('WS: connected');

        ws_connect_status = 'connected';

        dispatch('ws_conn', {
            'status': 'connected'
        });

        // ws_connection.send(JSON.stringify({
        //     client_id: client_id,
        //     target: 'echo',
        //     type: 'hello',
        //     group_id: group_id,
        //     msg: 'You are connected!'
        // }));

        ws_connection.send(JSON.stringify({
            client_id: client_id,
            target: 'all',
            type: 'hello',
            group_id: group_id,
            msg: `Client ${client_id.toString().slice(-5)} connected!`
        }));
    };

    ws_connection.onmessage = function(event) {
        if (log_lvl) {
            console.log('WS: message received', event);
        }

        let ws_recv_data = JSON.parse(event.data);
        if (log_lvl) {
            console.log('WS: Received data:', ws_recv_data);
        }

        if (client_id == ws_recv_data.client_id) {
            if (log_lvl) {
                console.log('WS: Message received was sent by self and is an echo that can be ignored.');
            }
            return false;
        }

        if (ws_recv_data.type == 'cmd') {
            console.log(`WS: Type CMD: ${ws_recv_data.cmd}`);
            ws_received_list_cmd.unshift(ws_recv_data); // Add to the beginning of the list
            // ws_received_list_cmd.push(ws_recv_data); // Add to the end of the list
            ws_received_list_cmd = ws_received_list_cmd; // trigger Svelte update -2024-10-04
        } else {
            console.log('WS: Type other');
            ws_received_list_other.unshift(ws_recv_data); // Add to the beginning of the list
            // ws_received_list_other.push(ws_recv_data); // Add to the end of the list
            ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
        }

        dispatch('ws_recv', {
            // 'client_id': ws_data.client_id, // The device or browser ID if available.
            'src': ws_recv_data.client_id, // The device or browser ID if available.
            // 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
            'dest': group_id, // Destination client
            'target': ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
            'type': ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
            // 'grp': ws_recv_data.grp, // Destination group
            'msg': ws_recv_data.msg, // Message string
            'cmd': ws_recv_data.cmd, // Command string
        });

    };

    ws_connection.onclose = function(event) {
        console.log('WS: connection closed');

        ws_connection.send(JSON.stringify({
            client_id: client_id,
            target: 'all',
            type: 'hello',
            group_id: group_id,
            msg: `Client ${client_id} is disconnecting!`
        }));

        ws_connect_status = 'disconnected';

        let fake_ws_recv_data = {
            'client_id': client_id,
            'target': 'local',
            'type': 'bye',
            'group_id': group_id,
            'msg': `LOCAL Client ${client_id} has disconnected!`
        };
        ws_received_list_other.unshift(fake_ws_recv_data);
        ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04

        dispatch('ws_conn', {
            'status': 'disconnected'
        });

        if (ws_connect) {
            setTimeout(function() {
                console.log('WS: Disconnected... Try again!');
                ws_connect_group_id({group_id: group_id, client_id: client_id});
                console.log('WS: Again done?');
            }, 1000);
        }

    };

    ws_connection.onerror = function(event) {
        console.log('WS: connection error???');

        ws_connection.send(JSON.stringify({
            client_id: client_id,
            target: 'all',
            type: 'hello',
            group_id: group_id,
            msg: `Client ${client_id} is having trouble?!`
        }));
    };

    // NOTE WARNING: Uncommenting this seems to break FastAPI somehow???
    // NOTE: from FastAPI log: RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.
    // ws_connection.onerror = function(err) {
    //     console.error('WS socket error: ', err.message, 'Closing socket');
    //     // ws_connection.close();
    // };

    return ws_connection;
}

// Start the WS function
let ws_group: any = null;
$: if (ws_connect && group_id) {
    ws_group = ws_connect_group_id({group_id: group_id, client_id: client_id});
} else {
    ws_group?.close();
}

$: if (trigger_send && cmd) {
    trigger_send = null;
    console.log('WS: Send triggered!');
    console.log(cmd);
    ws_data.target = 'group';
    ws_data.type = 'cmd';
    ws_data.cmd = cmd;
    handle_send_ws_data();
    cmd = '';
}

function handle_send_ws_data() {
    console.log(ws_data);
    if (!ws_data) {
        return false;
    }
    if (!ws_group) {
        console.log('WS: No connection!');
        return false;
    }
    let ws_data_json_str = JSON.stringify(ws_data);
    let resp = ws_group.send(ws_data_json_str);
    console.log(resp);

    dispatch('ws_sent', {
        // 'client_id': ws_data.client_id, // The device or browser ID if available.
        'src': ws_data.client_id, // The device or browser ID if available.
        // 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
        'dest': group_id, // Destination client
        'group_id': group_id,
        'target': ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
        'type': ws_data.type, // Message type (msg, cmd, json, hello, bye)
        // 'grp': ws_data.grp, // Destination group
        'msg': ws_data.msg, // Message string
        'cmd': ws_data.cmd, // Command string
    });

    cmd = '';
    msg = '';
}

</script>


<section class="ae_element__websocket container p-1 bg-pink-100 text-xs mx-auto pb-16 mt-32 mb-32 relative">

<span class="absolute top-0 right-0 flex flex-col gap-1">
    <button
        type="button"
        on:click={() => {
            hide__ws_form = !hide__ws_form;
        }}
        class="btn btn-sm text-xs hover:variant-filled-tertiary"
        class:variant-soft-tertiary={hide__ws_form}
        class:variant-filled-tertiary={!hide__ws_form}
        >
        {#if hide__ws_form}
            Show Form
        {:else}
            Hide Form?
        {/if}
    </button>
    <button
        type="button"
        on:click={() => {
            hide__ws_messages = !hide__ws_messages;
        }}
        class="btn btn-sm text-xs hover:variant-filled-tertiary"
        class:variant-soft-tertiary={hide__ws_messages}
        class:variant-filled-tertiary={!hide__ws_messages}
        >
        {#if hide__ws_messages}
            Show Messages
        {:else}
            Hide Messages?
        {/if}
    </button>
    <button
        type="button"
        on:click={() => {
            hide__ws_commands = !hide__ws_commands;
        }}
        class="btn btn-sm text-xs hover:variant-filled-tertiary"
        class:variant-soft-tertiary={hide__ws_commands}
        class:variant-filled-tertiary={!hide__ws_commands}
        >
        {#if hide__ws_commands}
            Show Commands
        {:else}
            Hide Commands?
        {/if}
    </button>
</span>

<header>

    <h1 class="h6 text-center">Websocket Messages &amp; Commands</h1>

</header>


<!-- <form on:submit|preventDefault={handle_send_message}>
    <select bind:value={type}>
        <option value="">None</option>
        <option value="echo">Echo</option>
        <option value="dm">Direct Message</option>
        <option value="group">Group Message</option>
        <option value="all">Broadcast to All</option>
        <option value="cmd">Command</option>
    </select>

    <select bind:value={group_id}>
        <option value="">None</option>
        <option value="test_grp_123">123</option>
        <option value="test_grp_999">999</option>
        <option value="test_grp_poster">A Poster Group</option>
    </select>

    <input type="text" bind:value={message_text} placeholder="Your message"/>

    <button>Send</button>
</form> -->

{#if !hide__ws_form}
<form
    on:submit|preventDefault={handle_send_ws_data}
    >
    <select
        bind:value={ws_data.type}
        class="input text-sm w-24"
        >
        <option value="">None</option>
        <option value="echo">Echo</option>
        <option value="dm">Direct Message</option>
        <option value="group">Group Message</option>
        <option value="all">Broadcast to All</option>
        <option value="cmd">Command</option>
    </select>
    <input type="text" bind:value={group_id} placeholder="Group ID" class="input text-sm w-36" />
    <!-- <select bind:value={group_id}>
        <option value="">None</option>
        <option value="test_grp_123">123</option>
        <option value="test_grp_999">999</option>
        <option value="test_grp_poster">A Poster Group</option>
    </select> -->

    <!-- <input type="text" bind:value={dm_client_id} placeholder="Direct message client ID"/> -->

    <input type="text" bind:value={ws_data.cmd} placeholder="Your command" class="input text-sm w-36" />
    <input type="text" bind:value={ws_data.msg} placeholder="Your message" class="input text-xs w-96" />

    <button
        type="submit"
        class="btn btn-sm variant-soft-warning"
        >Send Group</button>
</form>
{/if}

<!-- <pre>
ae_load:event_session=jEG9APQRUs8 (Poster Session #3: Work Never Ends - Pythagoras)
ae_open:event_file=CHqU5sW7xbc (jpg)
ae_open:event_file=Kljq0uiTlXt (video)
</pre> -->

<!-- <hr> -->

<section
    class:hidden={hide__ws_messages}
    >
<h2 class="text-center underline">Messages [grp, client, target, type]</h2>

<ol class="list-decimal list-outside max-h-24 overflow-y-auto messages">
    {#each ws_received_list_other as msg_entry, index}
        <li
            class="ml-4"
            >
            <div
                class="flex flex-row justify-between gap-1 w-full"
                >
                <span>
                    [{(msg_entry.group_id||'No Group ID')}]
                    {(msg_entry.client_id.toString().slice(-5)||'No Client ID')}
                    &ndash;
                    {(msg_entry.target||'No Target')}
                    |
                    <!-- &ndash; -->
                    {(msg_entry.type||'No Type')}:
                </span>
                <span class="justify-self-end">
                    "{msg_entry.msg}"
                </span>
                <!-- <br>{JSON.stringify(msg_entry)} -->
            </div>
        </li>
    {/each}
</ol>
</section> <!-- End Messages -->

<hr>

<section
    class:hidden={hide__ws_commands}
    >
<h2 class="text-center underline">Commands</h2>

<ol class="list-decimal list-outside max-h-24 overflow-y-auto commands">
    {#each ws_received_list_cmd as cmd_entry}
        <li
            class="ml-4"
            >
            <div
                class="flex flex-row justify-between gap-1 w-full"
                >
                <span>
                    [{(cmd_entry.group_id||'No Group ID')}]
                    {(cmd_entry.client_id.toString().slice(-5)||'No Client ID')}
                    &mdash;
                    {(cmd_entry.target||'No Target')}
                    |
                    <!-- &mdash; -->
                    {(cmd_entry.type||'No Type')}:
                </span>
                <span class="justify-self-end">
                    "{cmd_entry.cmd}"
                </span>
            </div>
        </li>
    {/each}
</ol>
</section> <!-- End Commands -->


</section>


<style>
/* .websocket_element {
    background-color: white;
    border-top: dashed medium gray;
    color: gray;
    font-size: .7em;
}
.websocket_element header {
    font-size: .7em;
}
.websocket_element h2 {
    font-size: .9em;
} */
</style>

