<!-- [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.
     * @PRE Needs a valid taskId to fetch logs for.
     * @POST task logs are displayed and updated in real time.
     * @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
     *
     * @TEST_CONTRACT Component_TaskLogViewer ->
     * {
     *   required_props: {taskId: string},
     *   optional_props: {show: boolean, inline: boolean, taskStatus: string, realTimeLogs: array},
     *   invariants: [
     *       "Fetches initial logs on mount if taskId is provided",
     *       "Updates log list when realTimeLogs prop changes without duplicating entries",
     *       "Displays Loading, Error, or Data states correctly"
     *   ]
     * }
     * @TEST_FIXTURE valid_viewer -> {taskId: "123", show: true}
     * @TEST_EDGE no_task_id -> does not fetch, shows empty/loading indefinitely if show=true
     * @TEST_EDGE api_error -> transitions to Error state and displays retry button
     * @TEST_INVARIANT displays_logs -> verifies: [valid_viewer]
     */
    import { onDestroy } from "svelte";
    import { getTaskLogs } from "../services/taskService.js";
    import { t } from "../lib/i18n";
    import TaskLogPanel from "./tasks/TaskLogPanel.svelte";

    let {
        show = $bindable(false),
        inline = false,
        taskId = null,
        taskStatus = null,
        realTimeLogs = [],
        onclose = () => {},
    } = $props();

    let logs = $state([]);
    let loading = $state(false);
    let error = $state("");
    let interval;
    let autoScroll = $state(true);

    let shouldShow = $derived(inline || show);

    // [DEF:handleRealTimeLogs:Action]
    // @PURPOSE: Sync real-time logs to the current log list
    // @PRE: None
    // @POST: logs are updated with new real-time log entries
    $effect(() => {
        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];
            }
        }
    });
    // [/DEF:handleRealTimeLogs:Action]

    // [DEF:fetchLogs:Function]
    // @PURPOSE: Fetches logs for a given task ID
    // @PRE: taskId is set
    // @POST: logs are populated with API response
    async function fetchLogs() {
        if (!taskId) return;
        try {
            console.log(`[TaskLogViewer][API][fetchLogs:STARTED] id=${taskId}`);
            logs = await getTaskLogs(taskId);
            console.log(`[TaskLogViewer][API][fetchLogs:SUCCESS] id=${taskId}`);
        } catch (e) {
            console.error(
                `[TaskLogViewer][API][fetchLogs:FAILED] id=${taskId}`,
                e,
            );
            error = e.message;
        } finally {
            loading = false;
        }
    }
    // [/DEF:fetchLogs:Function]

    // [DEF:handleFilterChange:Function]
    // @PURPOSE: Updates filter conditions for the log viewer
    // @PRE: event contains source and level fields
    // @POST: Log viewer filters updated
    function handleFilterChange(event) {
        console.log("[TaskLogViewer][UI][handleFilterChange:START]");
        const { source, level } = event;
    }
    // [/DEF:handleFilterChange:Function]

    // [DEF:handleRefresh:Function]
    // @PURPOSE: Refreshes the logs by polling the API
    // @PRE: None
    // @POST: Logs refetched
    function handleRefresh() {
        console.log("[TaskLogViewer][UI][handleRefresh:START]");
        fetchLogs();
    }
    // [/DEF:handleRefresh:Function]

    $effect(() => {
        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}
    <!-- [DEF:showInline:Component] -->
    <!-- @PURPOSE: Shows inline logs -->
    <!-- @LAYER: UI -->
    <!-- @SEMANTICS: logs, inline -->
    <!-- @TIER: STANDARD -->
    {#if inline}
        <div class="flex flex-col h-full w-full">
            {#if loading && logs.length === 0}
                <div
                    class="flex items-center justify-center gap-3 h-full text-terminal-text-subtle text-sm"
                >
                    <div
                        class="w-5 h-5 border-2 border-terminal-border border-t-primary rounded-full animate-spin"
                    ></div>
                    <span>{$t.tasks?.loading}</span>
                </div>
            {:else if error}
                <div
                    class="flex items-center justify-center gap-2 h-full text-log-error text-sm"
                >
                    <span class="text-xl">⚠</span>
                    <span>{error}</span>
                    <button
                        class="bg-terminal-surface text-terminal-text-subtle border border-terminal-border rounded-md px-3 py-1 text-xs cursor-pointer transition-all hover:bg-terminal-border hover:text-terminal-text-bright"
                        onclick={handleRefresh}>{$t.common?.retry}</button
                    >
                </div>
            {:else}
                <TaskLogPanel
                    {taskId}
                    {logs}
                    {autoScroll}
                    onfilterchange={handleFilterChange}
                />
            {/if}
        </div>
        <!-- [/DEF:showInline:Component] -->
    {:else}
        <!-- [DEF:showModal:Component] -->
        <!-- @PURPOSE: Shows modal logs -->
        <!-- @LAYER: UI -->
        <!-- @SEMANTICS: logs, modal -->
        <!-- @TIER: STANDARD -->
        <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/75 transition-opacity"
                    aria-hidden="true"
                    onclick={() => {
                        show = false;
                        onclose();
                    }}
                    onkeydown={(e) => {
                        if (e.key === "Escape") {
                            show = false;
                            onclose();
                        }
                    }}
                    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}
                            </h3>
                            <button
                                class="text-gray-500 hover:text-gray-300"
                                onclick={() => {
                                    show = false;
                                    onclose();
                                }}
                                aria-label={$t.common?.close}>✕</button
                            >
                        </div>
                        <div class="h-[500px]">
                            {#if loading && logs.length === 0}
                                <p class="text-gray-500 text-center">
                                    {$t.tasks?.loading}
                                </p>
                            {:else if error}
                                <p class="text-red-400 text-center">{error}</p>
                            {:else}
                                <TaskLogPanel
                                    {taskId}
                                    {logs}
                                    {autoScroll}
                                    onfilterchange={handleFilterChange}
                                />
                            {/if}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    {/if}
{/if}
// [/DEF:showModal:Component]

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