<script>
    import markdownit from 'markdown-it'
    import hljs from 'highlight.js';
    import ClipboardJS from 'clipboard';
    import ChatMessage from './ChatMessage.svelte';
    import Modal from './Modal.svelte';
    import AssistantForm from './AssistantForm.svelte';
    import { onMount } from 'svelte';

    // export let apiKey = '';
    export let proxyBaseUrl = '';
    export let model_list = [];

    let assistant = null;
    let assistant_id = 0;
    let assistant_title = '';
    let assistants = [];

    let messages = [];
    let newMessage = '';
    let chatContainer;
    let assistantForm; // Reference to the AssistantForm component
    let modal; // Reference to the Modal component

    onMount(() => {
		refreshAssistants();
        const clipboard = new ClipboardJS('.hljs-copy-button', {
            target: function(trigger) {
                console.log(trigger.parentNode.nextElementSibling)
                return trigger.parentNode.nextElementSibling;
            }
        });

        clipboard.on('success', function(e) {
            e.clearSelection();
        });
	});

    const md = markdownit({
        linkify: true,
        highlight(code, lang) {
            const language = hljs.getLanguage(lang) ? lang : 'plaintext';
            const html = hljs.highlight(code, {language: language, ignoreIllegals: true }).value;
            return '<pre class="hljs-code-container my-3">'
            + '<div class="hljs-code-header bg-light-subtle text-light-emphasis">' + `<span>${language}</span>`
            + '<button class="hljs-copy-button btn btn-secondary btn-sm" title="Copier le code">'
            + '<span class="icon-content_copy"></span></button></div>'
            + `<code class="hljs language-${language}">${html}</code>`
            + '</pre>';
        },
    });

    /*

    */

    async function postRequest(url, headers, body) {
        const response = await fetch(url, {
            method: "POST",
            headers: headers,
            body: JSON.stringify(body),
        });

        if (!response.ok) {
            throw new Error(await response.text());
        }

        return response;
    }

    async function readStream(stream, progressCallback) {
        const reader = stream.getReader();
        const textDecoder = new TextDecoder('utf-8');
        let responseObj = {};

        while (true) {
            const { done, value } = await reader.read();
            if (done) break;

            const lines = textDecoder.decode(value).split("\n");
            processLines(lines, responseObj, progressCallback);
        }

        return responseObj;
    }

    function processLines(lines, responseObj, progressCallback) {
        for (const line of lines) {
            if (line.startsWith("data: ")) {
                if (line.includes("[DONE]")) {
                    return responseObj;
                }
                try {
                    const data = JSON.parse(line.slice(6));
                    const delta = data.choices[0].delta;

                    Object.keys(delta).forEach(key => {
                        responseObj[key] = (responseObj[key] || "") + delta[key];
                        progressCallback(responseObj);
                    });

                } catch (e) {
                    console.log("Error parsing line:", line);
                }
            }
        }
    }

    async function complete(messages, apiUrl, params, progressCallback) {
        const headers = {
            "Content-Type": "application/json",
        };

        const body = {
            model: params.model,
            messages: messages,
            stream: true,
        };

        if (params.temperature != undefined) {
            body.temperature = params.temperature;
        }

        if (params.top_p != undefined) {
            body.top_p = params.top_p;
        }

        const response = await postRequest(apiUrl, headers, body);
        return readStream(response.body, progressCallback);
    }

    function sendMessage() {
        if (newMessage.trim() === '') return;

        if (!messages.length && assistant) {
            const systemMessage = { role: 'system', content: assistant.system_prompt };
            messages.push(systemMessage);
        }

        const userMessage = { role: 'user', content: newMessage };

        messages.push(userMessage);
        messages.push({ role: 'assistant', content: '' });
        messages = messages;
        const lastMsgIndex = messages.length - 1;

        try {
            if (assistant) {
                complete(
                    messages,
                    proxyBaseUrl,
                    // apiKey,
                    assistant,
                    (message) => {
                        if (message.content)
                            messages[lastMsgIndex].content = message.content;
                    }
                );
            } else if (!assistants.length) {
                messages[lastMsgIndex].content = "Aucun assistant n'a été trouvé. Veuillez en créer un nouveau en cliquant sur le bouton +.";
            }


        } catch (error) {
            console.log(error.message);
            return;
        } finally {
            newMessage = '';
        }
    }

    function clearMessages() {
        messages = [];
    }

    function loadAssistant(config = {}) {
        assistant = null;

        // ES6 Destructuring object properties into variables with default values
        const {
            model = '',
            system_prompt = '',
            temperature = 0,
            top_p = 0
        } = config;

        // ES6 (Property Shorthand)
        assistant = {model, system_prompt, temperature, top_p };

        assistant_id = config.id;
        assistant_title = config.title;

        document.title = assistant_title;

        // console.log("Changed assistant " + assistant_id);
        // console.log(assistant);
    }

    async function refreshAssistants() {

        try {
            const response = await fetch('/site/assistant/list', {method: 'GET'});

            if (!response.ok) {
                throw new Error('Failed to fetch assistants');
            }

            assistants = await response.json();

            if (assistants.length) {
                assistants.forEach(config => {
                    if (config.default == 1) {
                        loadAssistant(config);
                        return;
                    }
                });

                if (!assistant) {
                    loadAssistant(assistants[0]);
                }
            }

        } catch (error) {
            console.error('Error refreshing assistants:', error);
        }
    }

    // Handle saving assistant data
    async function handleSave(event) {
        try {
            const assistantData = event.detail;

            const response = await fetch('/site/assistant/save', {
                method: 'POST',
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify(assistantData),
            });

            if (!response.ok) {
                throw new Error('Server response error');
            }

            const data = await response.json();

            if (data.status == 'success') {
                refreshAssistants();
                modal.hide();
            } else if (data.status == 'error' && data.errors) {
                assistantForm.setErrors(data.errors);
            }

        } catch (error) {
            console.error('Error saving assistant:', error);
        }
    }

    // Handle changing assistant
    async function handleChange() {
        try {

            assistants.forEach(config => {
                if (config.id == assistant_id) {
                    loadAssistant(config);
                    return;
                }
            });

            const response = await fetch('/site/assistant/set-as-default?id=' + assistant_id);

            if (!response.ok) {
                throw new Error('Server response error');
            }

            const status = await response.json();

            if (!status) {
                throw new Error('Failed to set default assistant');
            }

        } catch (error) {
            console.error('Error changing assistant:', error);
        }
    }


    function createAssistant()
    {
        assistantForm.setAssistant({
            title: '',
            model: 'gpt-4o',
            system_prompt: '',
            temperature: 0,
            top_p: 1.0,
            default: 1
        });

        modal.show();
    }

    function editAssistant()
    {
        assistants.forEach(config => {
            if (config.id == assistant_id) {
                assistantForm.setAssistant(config);
                modal.show();
                return;
            }
        });
    }

    async function deleteAssistant()
    {
        if (assistant && confirm(`Êtes-vous certain de vouloir effacer l'assistant ${assistant_title} ?`)) {
            try {

                const response = await fetch('/site/assistant/delete?id=' + assistant_id);

                if (!response.ok) {
                    throw new Error('Server response error');
                }

                const status = await response.json();

                if (!status) {
                    throw new Error('Failed to delete assistant');
                }

                assistant = null;

                refreshAssistants();

            } catch (error) {
                console.error('Error deleting assistant:', error);
            }
        }
    }

    function exportMessages() {
        const date = new Date();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');

        const formattedDate = `${day}-${month}-${date.getFullYear()}`;
        const formattedTime = `${hours}-${minutes}-${seconds}`;

        const filename = `${assistant_title}_${formattedDate}_${formattedTime}.json`;

        const json = JSON.stringify(messages, null, 2);
        const blob = new Blob([json], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }

    // Fonction pour importer les messages depuis un fichier JSON
    function importMessages(event) {
        const file = event.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = (e) => {
            try {
                const importedMessages = JSON.parse(e.target.result);
                if (Array.isArray(importedMessages)) {
                    messages = importedMessages;
                } else {
                    throw new Error("Invalid JSON format");
                }
            } catch (error) {
                console.error("Error importing messages:", error);
            }
        };

        reader.readAsText(file);
    }

    /*
    import { onMount } from 'svelte';
    import { writable } from 'svelte/store';

    let messages = writable([]);
    let newMessage = writable("");

    const sendMessage = () => {
        if ($newMessage.trim() !== "") {
            messages.update(msgs => [...msgs, { role: 'user', content: $newMessage }]);
            newMessage.set("");
        }
    };

    // Sample function to simulate receiving a message from the AI
    const receiveMessage = (content) => {
        messages.update(msgs => [...msgs, { role: 'assistant', content }]);
    };

    onMount(() => {
        // Simulate receiving an initial message from the AI
        receiveMessage("Hello! How can I assist you today?");
    });
    */
</script>

<header>
    <h1 class="text-center fw-lighter">{assistant_title}</h1>

    <div class="toolbar">
        <button class="btn btn-primary" on:click={createAssistant} title="Créer un assistant"><span class="icon-add"></span></button>

        {#if assistants.length}
        <select class="form-select" bind:value={assistant_id} on:change={handleChange}>
            {#each assistants as config}
            <option value={config.id}>{config.title}</option>
            {/each}
        </select>
        {#if assistant}
        <button class="btn btn-secondary" on:click={editAssistant} title="Modifier l'assistant {assistant_title}"><span class="icon-edit"></span></button>
        <button class="btn btn-danger" on:click={deleteAssistant} title="Supprimer l'assistant {assistant_title}"><span class="icon-delete"></span></button>
        {/if}
        {/if}



        {#if messages.length}
        <div class="separator d-none d-sm-block"></div>
        <button class="btn btn-warning clear" on:click="{clearMessages}" title="Effacer les messages"><span class="icon-clean"></button>
        <button class="btn btn-info" on:click="{exportMessages}" title="Exporter la conversation"><span class="icon-file_download"></span></button>
        <div class="separator d-none d-sm-block"></div>
        {/if}



        <input id="import-file" type="file" accept=".json" on:change="{importMessages}" style="display:none" />
        <label for="import-file" class="btn btn-info"><span class="icon-file_upload" title="Importer une conversation"></span></label>

    </div>

</header>

<main>
    <div class="chat-container" bind:this="{chatContainer}" >
        {#each messages as message, index (index)}
        <ChatMessage message="{message}" container="{chatContainer.parentElement}" markdown={md} />
        {/each}
    </div>
</main>

<footer>
    <textarea class="chat-input" rows="1"
            bind:value="{newMessage}"
            on:keyup={e => { if (e.key === 'Enter') sendMessage(); }}
            placeholder="Saisissez votre message ici..."
            aria-label="Chat with AI"></textarea>
</footer>

<Modal bind:this="{modal}" ariaLabelledby="editAssistantModal">
    <AssistantForm models={model_list} bind:this={assistantForm} on:save={handleSave} />
</Modal>

<style lang="scss">

    header {
        background-color:  #333;
        color: white;
        padding: 8px;
    }


    .toolbar {
        display: flex;
        justify-content: center;
        gap: 10px;
        flex-wrap: wrap;

        .separator {
            background-color:  #4a4a4a;
            width: 1px;
            margin: 0 15px;
        }

        & > select {
            width: auto;
        }

        /*
        & > button {

        }
        */
    }

    main {
      flex-grow: 1;
      overflow-y: auto;
    }

    button.clear {
        right: 0;
    }

    footer {
        width: 100%;
        padding: 8px;
        display: flex;
        justify-content: center;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
    }

    .chat-input {
        width: 100%;
        max-width: 768px;
        padding: 8px;
        border-width: 1px;
        border-color: rgba(0, 0, 0, 0.1);
        border-radius: 6px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
        min-height: 40px;
    }

    .chat-container {
        display: flex;
        flex-direction: column;
        width: 100%;
        max-width: 768px;
        margin: 0 auto;
        overflow-wrap: break-word;
    }
</style>

