<!-- [DEF:TaskLogViewer:Component] -->
<!--
@TIER: CRITICAL
@SEMANTICS: task, log, viewer, inline, realtime
@PURPOSE: Displays task logs inline (in drawer) or as modal. Merges real-time WebSocket logs with polled historical logs.
@LAYER: UI
@RELATION: USES -> frontend/src/services/taskService.js
@RELATION: USES -> frontend/src/components/tasks/TaskLogPanel.svelte
@INVARIANT: Real-time logs are always appended without duplicates.
-->
<script>
    /**
     * @TIER CRITICAL
     * @PURPOSE Displays detailed logs for a specific task inline or in a modal using TaskLogPanel.
     * @UX_STATE Loading -> Shows spinner/text while fetching initial logs
     * @UX_STATE Streaming -> Displays logs with auto-scroll, real-time appending
     * @UX_STATE Error -> Shows error message with recovery option
     * @UX_FEEDBACK Auto-scroll keeps newest logs visible
     * @UX_RECOVERY Refresh button re-fetches logs from API
     */
    import { createEventDispatcher, onDestroy } from "svelte";
    import { getTaskLogs } from "../services/taskService.js";
    import { t } from "../lib/i18n";
    import TaskLogPanel from "./tasks/TaskLogPanel.svelte";

    export let show = false;
    export let inline = false;
    export let taskId = null;
    export let taskStatus = null;
    export let realTimeLogs = [];

    const dispatch = createEventDispatcher();

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

    $: shouldShow = inline || show;

    // [DEF:handleRealTimeLogs:Action]
    /** @PURPOSE Append real-time logs as they arrive from WebSocket, preventing duplicates */
    $: if (realTimeLogs && realTimeLogs.length > 0) {
        const lastLog = realTimeLogs[realTimeLogs.length - 1];
        const exists = logs.some(
            (l) =>
                l.timestamp === lastLog.timestamp &&
                l.message === lastLog.message,
        );
        if (!exists) {
            logs = [...logs, lastLog];
            console.log(
                `[TaskLogViewer][Action] Appended real-time log, total=${logs.length}`,
            );
        }
    }
    // [/DEF:handleRealTimeLogs:Action]

    // [DEF:fetchLogs:Function]
    /**
     * @PURPOSE Fetches logs for the current task from API (polling fallback).
     * @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(`[TaskLogViewer][Action] Fetching logs for task=${taskId}`);
        try {
            logs = await getTaskLogs(taskId);
            console.log(
                `[TaskLogViewer][Coherence:OK] Logs fetched count=${logs.length}`,
            );
        } catch (e) {
            error = e.message;
            console.error(
                `[TaskLogViewer][Coherence:Failed] Error: ${e.message}`,
            );
        } finally {
            loading = false;
        }
    }
    // [/DEF:fetchLogs:Function]

    function handleFilterChange(event) {
        const { source, level } = event.detail;
        console.log(
            `[TaskLogViewer][Action] Filter changed: source=${source}, level=${level}`,
        );
    }

    function handleRefresh() {
        console.log(`[TaskLogViewer][Action] Manual refresh`);
        fetchLogs();
    }

    // React to changes in show/taskId/taskStatus
    $: if (shouldShow && taskId) {
        if (interval) clearInterval(interval);
        logs = [];
        loading = true;
        error = "";
        fetchLogs();

        if (
            taskStatus === "RUNNING" ||
            taskStatus === "AWAITING_INPUT" ||
            taskStatus === "AWAITING_MAPPING"
        ) {
            interval = setInterval(fetchLogs, 5000);
        }
    } else {
        if (interval) clearInterval(interval);
    }

    onDestroy(() => {
        if (interval) clearInterval(interval);
    });
</script>

{#if shouldShow}
    {#if inline}
        <div class="log-viewer-inline">
            {#if loading && logs.length === 0}
                <div class="loading-state">
                    <div class="loading-spinner"></div>
                    <span>{$t.tasks?.loading || "Loading logs..."}</span>
                </div>
            {:else if error}
                <div class="error-state">
                    <span class="error-icon">⚠</span>
                    <span>{error}</span>
                    <button class="retry-btn" on:click={handleRefresh}
                        >Retry</button
                    >
                </div>
            {:else}
                <TaskLogPanel
                    {taskId}
                    {logs}
                    {autoScroll}
                    on:filterChange={handleFilterChange}
                    on:refresh={handleRefresh}
                />
            {/if}
        </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"
            >
                <div
                    class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
                    aria-hidden="true"
                    on:click={() => {
                        show = false;
                        dispatch("close");
                    }}
                    on:keydown={(e) => e.key === "Escape" && (show = false)}
                    role="presentation"
                ></div>

                <div
                    class="inline-block align-bottom bg-gray-900 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="p-6">
                        <div class="flex justify-between items-center mb-4">
                            <h3
                                class="text-lg font-medium text-gray-100"
                                id="modal-title"
                            >
                                {$t.tasks?.logs_title || "Task Logs"}
                            </h3>
                            <button
                                class="text-gray-500 hover:text-gray-300"
                                on:click={() => {
                                    show = false;
                                    dispatch("close");
                                }}
                                aria-label="Close">✕</button
                            >
                        </div>
                        <div class="h-[500px]">
                            {#if loading && logs.length === 0}
                                <p class="text-gray-500 text-center">
                                    {$t.tasks?.loading || "Loading..."}
                                </p>
                            {:else if error}
                                <p class="text-red-400 text-center">{error}</p>
                            {:else}
                                <TaskLogPanel
                                    {taskId}
                                    {logs}
                                    {autoScroll}
                                    on:filterChange={handleFilterChange}
                                />
                            {/if}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    {/if}
{/if}

<!-- [/DEF:TaskLogViewer:Component] -->

<style>
    .log-viewer-inline {
        display: flex;
        flex-direction: column;
        height: 100%;
        width: 100%;
    }

    .loading-state {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.75rem;
        height: 100%;
        color: #64748b;
        font-size: 0.875rem;
    }

    .loading-spinner {
        width: 1.25rem;
        height: 1.25rem;
        border: 2px solid #334155;
        border-top-color: #3b82f6;
        border-radius: 50%;
        animation: spin 0.8s linear infinite;
    }

    @keyframes spin {
        to {
            transform: rotate(360deg);
        }
    }

    .error-state {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
        height: 100%;
        color: #f87171;
        font-size: 0.875rem;
    }

    .error-icon {
        font-size: 1.25rem;
    }

    .retry-btn {
        background-color: #1e293b;
        color: #94a3b8;
        border: 1px solid #334155;
        border-radius: 0.375rem;
        padding: 0.25rem 0.75rem;
        font-size: 0.75rem;
        cursor: pointer;
        transition: all 0.15s;
    }

    .retry-btn:hover {
        background-color: #334155;
        color: #e2e8f0;
    }
</style>
