<!-- [DEF:TaskLogViewer:Component] -->
<!--
@SEMANTICS: task, log, viewer, modal, inline
@PURPOSE: Displays detailed logs for a specific task in a modal or inline.
@LAYER: UI
@RELATION: USES -> frontend/src/services/taskService.js
-->
<script>
    import { createEventDispatcher, onMount, onDestroy } from 'svelte';
    import { getTaskLogs } from '../services/taskService.js';

    export let show = false;
    export let inline = false;
    export let taskId = null;
    export let taskStatus = null; // To know if we should poll

    const dispatch = createEventDispatcher();

    let logs = [];
    let loading = false;
    let error = "";
    let interval;
    let autoScroll = true;
    let logContainer;

    $: shouldShow = inline || show;

    // [DEF:fetchLogs:Function]
    /**
     * @purpose Fetches logs for the current task.
     * @pre taskId must be set.
     * @post logs array is updated with data from taskService.
     * @side_effect Updates logs, loading, and error state.
     */
    async function fetchLogs() {
        if (!taskId) return;
        console.log(`[fetchLogs][Action] Fetching logs for task context={{'taskId': '${taskId}'}}`);
        try {
            logs = await getTaskLogs(taskId);
            if (autoScroll) {
                scrollToBottom();
            }
            console.log(`[fetchLogs][Coherence:OK] Logs fetched context={{'count': ${logs.length}}}`);
        } catch (e) {
            error = e.message;
            console.error(`[fetchLogs][Coherence:Failed] Error fetching logs context={{'error': '${e.message}'}}`);
        } finally {
            loading = false;
        }
    }
    // [/DEF:fetchLogs:Function]

    // [DEF:scrollToBottom:Function]
    /**
     * @purpose Scrolls the log container to the bottom.
     * @pre logContainer element must be bound.
     * @post logContainer scrollTop is set to scrollHeight.
     */
    function scrollToBottom() {
        if (logContainer) {
            setTimeout(() => {
                logContainer.scrollTop = logContainer.scrollHeight;
            }, 0);
        }
    }
    // [/DEF:scrollToBottom:Function]

    // [DEF:handleScroll:Function]
    /**
     * @purpose Updates auto-scroll preference based on scroll position.
     * @pre logContainer scroll event fired.
     * @post autoScroll boolean is updated.
     */
    function handleScroll() {
        if (!logContainer) return;
        // If user scrolls up, disable auto-scroll
        const { scrollTop, scrollHeight, clientHeight } = logContainer;
        const atBottom = scrollHeight - scrollTop - clientHeight < 50;
        autoScroll = atBottom;
    }
    // [/DEF:handleScroll:Function]

    // [DEF:close:Function]
    /**
     * @purpose Closes the log viewer modal.
     * @pre Modal is open.
     * @post Modal is closed and close event is dispatched.
     */
    function close() {
        dispatch('close');
        show = false;
    }
    // [/DEF:close:Function]

    // [DEF:getLogLevelColor:Function]
    /**
     * @purpose Returns the CSS color class for a given log level.
     * @pre level string is provided.
     * @post Returns tailwind color class string.
     */
    function getLogLevelColor(level) {
        switch (level) {
            case 'INFO': return 'text-blue-600';
            case 'WARNING': return 'text-yellow-600';
            case 'ERROR': return 'text-red-600';
            case 'DEBUG': return 'text-gray-500';
            default: return 'text-gray-800';
        }
    }
    // [/DEF:getLogLevelColor:Function]

    // React to changes in show/taskId/taskStatus
    $: if (shouldShow && taskId) {
        if (interval) clearInterval(interval);
        
        logs = [];
        loading = true;
        error = "";
        fetchLogs();
        
        // Poll if task is running
        if (taskStatus === 'RUNNING' || taskStatus === 'AWAITING_INPUT' || taskStatus === 'AWAITING_MAPPING') {
            interval = setInterval(fetchLogs, 3000);
        }
    } else {
        if (interval) clearInterval(interval);
    }

    // [DEF:onDestroy:Function]
    /**
     * @purpose Cleans up the polling interval.
     * @pre Component is being destroyed.
     * @post Polling interval is cleared.
     */
    onDestroy(() => {
        if (interval) clearInterval(interval);
    });
    // [/DEF:onDestroy:Function]
</script>

{#if shouldShow}
    {#if inline}
        <div class="flex flex-col h-full w-full p-4">
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-lg font-medium text-gray-900">
                    Task Logs <span class="text-sm text-gray-500 font-normal">({taskId})</span>
                </h3>
                <button on:click={fetchLogs} class="text-sm text-indigo-600 hover:text-indigo-900">Refresh</button>
            </div>
            
            <div class="flex-1 border rounded-md bg-gray-50 p-4 overflow-y-auto font-mono text-sm" 
                 bind:this={logContainer}
                 on:scroll={handleScroll}>
                {#if loading && logs.length === 0}
                    <p class="text-gray-500 text-center">Loading logs...</p>
                {:else if error}
                    <p class="text-red-500 text-center">{error}</p>
                {:else if logs.length === 0}
                    <p class="text-gray-500 text-center">No logs available.</p>
                {:else}
                    {#each logs as log}
                        <div class="mb-1 hover:bg-gray-100 p-1 rounded">
                            <span class="text-gray-400 text-xs mr-2">
                                {new Date(log.timestamp).toLocaleTimeString()}
                            </span>
                            <span class="font-bold text-xs mr-2 w-16 inline-block {getLogLevelColor(log.level)}">
                                [{log.level}]
                            </span>
                            <span class="text-gray-800 break-words">
                                {log.message}
                            </span>
                            {#if log.context}
                                <div class="ml-24 text-xs text-gray-500 mt-1 bg-gray-100 p-1 rounded overflow-x-auto">
                                    <pre>{JSON.stringify(log.context, null, 2)}</pre>
                                </div>
                            {/if}
                        </div>
                    {/each}
                {/if}
            </div>
        </div>
    {:else}
        <div class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
            <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
                <!-- Background overlay -->
                <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true" on:click={close}></div>

                <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

                <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
                    <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                        <div class="sm:flex sm:items-start">
                            <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full">
                                <h3 class="text-lg leading-6 font-medium text-gray-900 flex justify-between items-center" id="modal-title">
                                    <span>Task Logs <span class="text-sm text-gray-500 font-normal">({taskId})</span></span>
                                    <button on:click={fetchLogs} class="text-sm text-indigo-600 hover:text-indigo-900">Refresh</button>
                                </h3>
                                
                                <div class="mt-4 border rounded-md bg-gray-50 p-4 h-96 overflow-y-auto font-mono text-sm" 
                                     bind:this={logContainer}
                                     on:scroll={handleScroll}>
                                    {#if loading && logs.length === 0}
                                        <p class="text-gray-500 text-center">Loading logs...</p>
                                    {:else if error}
                                        <p class="text-red-500 text-center">{error}</p>
                                    {:else if logs.length === 0}
                                        <p class="text-gray-500 text-center">No logs available.</p>
                                    {:else}
                                        {#each logs as log}
                                            <div class="mb-1 hover:bg-gray-100 p-1 rounded">
                                                <span class="text-gray-400 text-xs mr-2">
                                                    {new Date(log.timestamp).toLocaleTimeString()}
                                                </span>
                                                <span class="font-bold text-xs mr-2 w-16 inline-block {getLogLevelColor(log.level)}">
                                                    [{log.level}]
                                                </span>
                                                <span class="text-gray-800 break-words">
                                                    {log.message}
                                                </span>
                                                {#if log.context}
                                                    <div class="ml-24 text-xs text-gray-500 mt-1 bg-gray-100 p-1 rounded overflow-x-auto">
                                                        <pre>{JSON.stringify(log.context, null, 2)}</pre>
                                                    </div>
                                                {/if}
                                            </div>
                                        {/each}
                                    {/if}
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                        <button
                            type="button"
                            class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
                            on:click={close}
                        >
                            Close
                        </button>
                    </div>
                </div>
            </div>
        </div>
    {/if}
{/if}
<!-- [/DEF:TaskLogViewer:Component] -->