<!-- #region LLMReportPage [C:3] [TYPE Page] [SEMANTICS sveltekit, llm, report, validation, screenshot] -->
<!-- @BRIEF Page component: routes/reports/llm/[taskId]/+page.svelte -->
<!-- @LAYER Page -->
<script lang="ts">
  /**
   * @PURPOSE: Full report page for LLM dashboard validation task execution.
   * @LAYER UI
   * @RELATION CALLS -> /api/tasks/{taskId}, /api/tasks/{taskId}/logs
   * @RELATION BINDS_TO -> PageStore
   * @UX_STATE: Loading -> Skeleton placeholders visible.
   * @UX_STATE: Loaded -> Full report with durations, screenshots, sent logs and task logs.
   * @UX_STATE: Error -> Alert with retry action.
   * @UX_FEEDBACK: Refresh button reloads report payload.
   * @UX_RECOVERY: Retry via refresh button after API error.
   * @TEST_DATA: llm_report_success -> {"task":{"id":"task-1","plugin_id":"llm_dashboard_validation","status":"SUCCESS","started_at":"2026-02-26T12:00:00Z","finished_at":"2026-02-26T12:00:10Z","result":{"summary":"OK","issues":[],"screenshot_paths":["/tmp/s1.png"],"logs_sent_to_llm":["[2026-02-26] explore_json"],"timings":{"validation_duration_ms":10000}}},"logs":[{"timestamp":"2026-02-26T12:00:01Z","level":"INFO","source":"llm","message":"Analyzing"}]}
   * @TEST_DATA: llm_report_error -> {"error":"Failed to load LLM report"}
   *
   * @TEST_CONTRACT Page_LLMReport ->
   * {
   *   required_props: {},
   *   optional_props: {},
   *   invariants: [
   *       "Loads specific task details and logs based on the URL parameter `taskId`",
   *       "Renders detailed statistics seamlessly considering possible missing payload elements",
   *       "Handles missing and non-null validation durations safely"
   *   ]
   * }
  * @TEST_FIXTURE init_state -> {"taskId": "task-1"}
  * @TEST_INVARIANT correct_fetch -> verifies: [init_state]
   */
  import { onDestroy, onMount, untrack } from "svelte";
  import { page } from "$app/state";
  import { goto } from "$app/navigation";
  import { api } from "$lib/api.js";
  import { t } from "$lib/i18n/index.svelte.js";
  import { openDrawerForTask } from "$lib/stores/taskDrawer.svelte.js";
  import Icon from "$lib/ui/Icon.svelte";

  let taskId = $derived(page.params.taskId);

  let task = $state(null);
  let logs = $state([]);
  let isLoading = $state(true);
  let error = $state(null);
  let screenshotBlobUrls = $state({});
  let screenshotLoadErrors = $state({});
  let screenshotLoadToken = $state(0);

  function formatDate(value) {
    if (!value) return "-";
    const parsed = new Date(value);
    if (Number.isNaN(parsed.getTime())) return "-";
    return `${parsed.toLocaleDateString()} ${parsed.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" })}`;
  }

  function formatMs(value) {
    const ms = Number(value);
    if (!Number.isFinite(ms) || ms < 0) return "-";
    if (ms < 1000) return `${ms} ms`;
    return `${(ms / 1000).toFixed(2)} s`;
  }

  function getDashboardCheckResult(resultPayload) {
    const rawStatus = String(resultPayload?.status || "").toUpperCase();
    if (rawStatus === "FAIL")
      return { label: "FAIL", level: "fail", icon: "!" };
    if (rawStatus === "WARN")
      return { label: "WARN", level: "warn", icon: "!" };
    if (rawStatus === "PASS")
      return { label: "PASS", level: "pass", icon: "OK" };
    return { label: "UNKNOWN", level: "unknown", icon: "?" };
  }

  function getCheckResultClasses(level) {
    if (level === "fail") return "bg-rose-100 text-rose-700 border-rose-200";
    if (level === "warn") return "bg-amber-100 text-amber-700 border-amber-200";
    if (level === "pass")
      return "bg-emerald-100 text-emerald-700 border-emerald-200";
    return "bg-slate-100 text-slate-700 border-slate-200";
  }

  async function loadReport() {
    if (!taskId) return;
    isLoading = true;
    error = null;
    try {
      const [taskPayload, logsPayload] = await Promise.all([
        api.getTask(taskId),
        api.getTaskLogs(taskId, { limit: 1000 }),
      ]);
      task = taskPayload;
      logs = Array.isArray(logsPayload) ? logsPayload : [];
    } catch (err) {
      error = err?.message || $t.reports?.load_failed || "Failed to load LLM report";
    } finally {
      isLoading = false;
    }
  }

  function backToReports() {
    goto("/reports");
  }

  function openTaskDetails() {
    if (!taskId) return;
    openDrawerForTask(taskId);
  }

  function cleanupScreenshotBlobUrls() {
    Object.values(screenshotBlobUrls).forEach((url) => {
      if (url) URL.revokeObjectURL(url);
    });
    screenshotBlobUrls = {};
  }

  async function loadScreenshotBlobUrls(paths) {
    const currentToken = ++screenshotLoadToken;
    cleanupScreenshotBlobUrls();
    screenshotLoadErrors = {};

    if (!Array.isArray(paths) || paths.length === 0) return;

    const nextUrls = {};
    const nextErrors = {};

    await Promise.all(
      paths.map(async (path) => {
        try {
          const blob = await api.getStorageFileBlob(path);
          nextUrls[path] = URL.createObjectURL(blob);
        } catch (err) {
          nextErrors[path] = err?.message || $t.reports?.llm_failed_screenshot || "Failed to load screenshot";
        }
      }),
    );

    if (currentToken !== screenshotLoadToken) {
      Object.values(nextUrls).forEach((url) => URL.revokeObjectURL(url));
      return;
    }

    screenshotBlobUrls = nextUrls;
    screenshotLoadErrors = nextErrors;
  }

  function openScreenshot(path) {
    const url = screenshotBlobUrls[path];
    if (!url) return;
    window.open(url, "_blank", "noopener,noreferrer");
  }

  onMount(async () => {
    await loadReport();
  });

  onDestroy(() => {
    cleanupScreenshotBlobUrls();
  });

  let result = $derived(task?.result || {});
  let checkResult = $derived(getDashboardCheckResult(result));
  let timings = $derived(result?.timings || {});
  let screenshotPaths = $derived(
    Array.isArray(result?.screenshot_paths)
      ? result.screenshot_paths
      : result?.screenshot_path
        ? [result.screenshot_path]
        : [],
  );
  let sentLogs = $derived(
    Array.isArray(result?.logs_sent_to_llm) ? result.logs_sent_to_llm : [],
  );

  $effect(() => {
    const paths = screenshotPaths;
    untrack(() => {
      void loadScreenshotBlobUrls(paths);
    });
  });
</script>

<div class="mx-auto w-full max-w-7xl space-y-6">
  <div class="flex items-start justify-between">
    <div>
      <button
        class="inline-flex items-center gap-2 rounded-lg px-2 py-1 text-sm text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
        onclick={backToReports}
      >
        <Icon name="chevronLeft" size={16} />
        {$t.nav?.reports || "Reports"}
      </button>
      <h1 class="mt-2 text-2xl font-bold text-slate-900">
        {$t.tasks?.result_llm_validation || "LLM Validation Report"}
      </h1>
      <p class="mt-1 text-sm text-slate-500">{$t.reports?.llm_task_id?.replace("{taskId}", taskId) || `Task: ${taskId}`}</p>
    </div>
    <div class="flex items-center gap-2">
      <button
        class="inline-flex items-center justify-center rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50"
        onclick={openTaskDetails}
      >
        {$t.tasks?.details_logs || "Task details and logs"}
      </button>
      <button
        class="inline-flex items-center justify-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary-hover"
        onclick={loadReport}
      >
        {$t.common?.refresh || "Refresh"}
      </button>
    </div>
  </div>

  {#if error}
    <div
      class="rounded-lg border border-rose-300 bg-rose-50 px-4 py-3 text-rose-700"
    >
      <div>{error}</div>
    </div>
  {/if}

  {#if isLoading}
    <div class="space-y-3">
      <div
        class="h-24 animate-pulse rounded-xl border border-slate-200 bg-white"
      ></div>
      <div
        class="h-64 animate-pulse rounded-xl border border-slate-200 bg-white"
      ></div>
      <div
        class="h-64 animate-pulse rounded-xl border border-slate-200 bg-white"
      ></div>
    </div>
  {:else if task}
    <div class="grid grid-cols-1 gap-4 md:grid-cols-5">
      <div class="rounded-xl border border-slate-200 bg-white p-4">
        <p class="text-xs font-semibold uppercase tracking-wide text-slate-500">
          {$t.reports?.llm_status || "Status"}
        </p>
        <p class="mt-2 text-lg font-semibold text-slate-900">
          {task?.status || "-"}
        </p>
      </div>
      <div class="rounded-xl border border-slate-200 bg-white p-4">
        <p class="text-xs font-semibold uppercase tracking-wide text-slate-500">
          {$t.reports?.llm_dashboard_check || "Dashboard check"}
        </p>
        <span
          class={`mt-2 inline-flex items-center gap-1 rounded-full border px-2 py-1 text-sm font-semibold uppercase ${getCheckResultClasses(checkResult.level)}`}
        >
          <span
            class="inline-flex min-w-[18px] items-center justify-center rounded-full bg-white/70 px-1 text-[10px] font-bold"
          >
            {checkResult.icon}
          </span>
          {checkResult.label}
        </span>
      </div>
      <div class="rounded-xl border border-slate-200 bg-white p-4">
        <p class="text-xs font-semibold uppercase tracking-wide text-slate-500">
          {$t.common?.started || "Started"}
        </p>
        <p class="mt-2 text-sm font-semibold text-slate-900">
          {formatDate(task?.started_at)}
        </p>
      </div>
      <div class="rounded-xl border border-slate-200 bg-white p-4">
        <p class="text-xs font-semibold uppercase tracking-wide text-slate-500">
          {$t.common?.finished || "Finished"}
        </p>
        <p class="mt-2 text-sm font-semibold text-slate-900">
          {formatDate(task?.finished_at)}
        </p>
      </div>
      <div class="rounded-xl border border-slate-200 bg-white p-4">
        <p class="text-xs font-semibold uppercase tracking-wide text-slate-500">
          {$t.common?.duration || "Duration"}
        </p>
        <p class="mt-2 text-lg font-semibold text-slate-900">
          {formatMs(timings?.validation_duration_ms)}
        </p>
      </div>
    </div>

    <div class="rounded-xl border border-slate-200 bg-white p-4">
      <h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
        {$t.reports?.llm_text_report || "Text Report"}
      </h2>
      <p class="mt-2 text-sm text-slate-800">{result?.summary || "-"}</p>
      {#if Array.isArray(result?.issues) && result.issues.length > 0}
        <div class="mt-4 space-y-2">
          {#each result.issues as issue}
            <div
              class="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm"
            >
              <div class="font-semibold text-slate-900">
                {issue?.severity || "INFO"}
              </div>
              <div class="text-slate-700">{issue?.message || "-"}</div>
              {#if issue?.location}
                <div class="text-xs text-slate-500">
                  {$t.reports?.llm_location?.replace("{location}", issue.location) || `Location: ${issue.location}`}
                </div>
              {/if}
            </div>
          {/each}
        </div>
      {/if}
    </div>

    <div class="rounded-xl border border-slate-200 bg-white p-4">
      <h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
        {$t.reports?.llm_screenshots || "Screenshots"}
      </h2>
      {#if screenshotPaths.length === 0}
        <p class="mt-2 text-sm text-slate-500">{$t.reports?.llm_no_screenshots || "No screenshots saved."}</p>
      {:else}
        <div class="mt-3 grid grid-cols-1 gap-4 lg:grid-cols-2">
          {#each screenshotPaths as path}
            <button
              type="button"
              class="block w-full text-left"
              onclick={() => openScreenshot(path)}
              disabled={!screenshotBlobUrls[path]}
            >
              {#if screenshotBlobUrls[path]}
                <img
                  src={screenshotBlobUrls[path]}
                  alt={$t.reports?.llm_screenshots || "Validation screenshot"}
                  class="h-64 w-full rounded-lg border border-slate-200 object-cover"
                />
              {:else}
                <div
                  class="flex h-64 w-full items-center justify-center rounded-lg border border-rose-200 bg-rose-50 px-4 text-sm text-rose-700"
                >
                  {screenshotLoadErrors[path] || $t.reports?.llm_failed_screenshot || "Failed to load screenshot"}
                </div>
              {/if}
              <p class="mt-1 truncate text-xs text-slate-500">{path}</p>
            </button>
          {/each}
        </div>
      {/if}
    </div>

    <div class="rounded-xl border border-slate-200 bg-white p-4">
      <h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
        {$t.reports?.llm_logs_sent?.replace("{count}", sentLogs.length) || `Logs sent to LLM (${sentLogs.length})`}
      </h2>
      {#if sentLogs.length === 0}
        <p class="mt-2 text-sm text-slate-500">{$t.reports?.llm_no_source_logs || "No source logs were attached."}</p>
      {:else}
        <pre
          class="mt-3 max-h-80 overflow-auto rounded-lg bg-slate-900 p-3 text-xs text-slate-100">{sentLogs.join(
            "\n",
          )}</pre>
      {/if}
    </div>

    <div class="rounded-xl border border-slate-200 bg-white p-4">
      <h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
        {$t.reports?.llm_task_logs?.replace("{count}", logs.length) || `Task execution logs (${logs.length})`}
      </h2>
      {#if logs.length === 0}
        <p class="mt-2 text-sm text-slate-500">{$t.reports?.llm_no_task_logs || "No task logs available."}</p>
      {:else}
        <div
          class="mt-3 max-h-96 overflow-auto rounded-lg border border-slate-200"
        >
          <table class="min-w-full divide-y divide-slate-200 text-xs">
            <thead class="bg-slate-50">
              <tr>
                <th class="px-3 py-2 text-left font-semibold text-slate-600"
                  >{$t.reports?.llm_time || "Time"}</th
                >
                <th class="px-3 py-2 text-left font-semibold text-slate-600"
                  >{$t.reports?.llm_level || "Level"}</th
                >
                <th class="px-3 py-2 text-left font-semibold text-slate-600"
                  >{$t.reports?.llm_source || "Source"}</th
                >
                <th class="px-3 py-2 text-left font-semibold text-slate-600"
                  >{$t.reports?.llm_message || "Message"}</th
                >
              </tr>
            </thead>
            <tbody class="divide-y divide-slate-100">
              {#each logs as logEntry}
                <tr>
                  <td class="px-3 py-2 align-top text-slate-600"
                    >{formatDate(logEntry?.timestamp)}</td
                  >
                  <td class="px-3 py-2 align-top text-slate-700"
                    >{logEntry?.level || "-"}</td
                  >
                  <td class="px-3 py-2 align-top text-slate-700"
                    >{logEntry?.source || "-"}</td
                  >
                  <td
                    class="px-3 py-2 align-top text-slate-800 whitespace-pre-wrap"
                    >{logEntry?.message || "-"}</td
                  >
                </tr>
              {/each}
            </tbody>
          </table>
        </div>
      {/if}
    </div>
  {/if}
</div>

<!-- #endregion LLMReportPage -->
