<script setup lang="ts">
// SPEC: PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-01040104 响应布局; PJ2026-01040106 Trace阅读.
// Responsibility: Session rail list, low-noise session details, local resize, and collapse UI state.

import { computed, ref } from "vue";
import { useWorkbenchStore } from "@/stores/workbench";
import { useClipboard } from "@/composables/useClipboard";
import LoadingState from "@/components/common/LoadingState.vue";
import { formatDisplayDateTime } from "@/config/runtime";
import { workbenchSessionPath } from "@/utils";

const workbench = useWorkbenchStore();
const { copied, copy } = useClipboard();
const COLLAPSED_STORAGE_KEY = "hwlab.workbench.sessionRailCollapsed.v1";
const width = ref(readWidth());
const collapsed = ref(readCollapsed());
const dragging = ref(false);
const detailOpen = ref(false);
const activeTab = computed(() => workbench.sessionTabs.find((tab) => tab.active) ?? null);
const activeSessionUrl = computed(() => activeTab.value ? sessionUrl(activeTab.value) : "");
const railStyle = computed(() => ({ width: collapsed.value ? "48px" : `${width.value}px` }));
const showSessionListLoading = computed(() => workbench.sessionListLoading);

function copyActive(): void {
  const tab = activeTab.value;
  if (!tab) return;
  void copy(`url=${sessionUrl(tab)}\nsessionId=${tab.sessionId ?? ''}\nthreadId=${tab.threadId ?? ''}\ntraceId=${tab.lastTraceId ?? ''}\nstatus=${tab.status ?? ''}\nupdatedAt=${tab.updatedAt ?? tab.startedAt ?? ''}`);
}

function sessionUrl(tab: { sessionId?: string | null }): string {
  const url = new URL(workbenchSessionPath(tab.sessionId || ""), window.location.origin);
  return url.toString();
}

function startResize(event: PointerEvent): void {
  if (collapsed.value) return;
  dragging.value = true;
  const startX = event.clientX;
  const startWidth = width.value;
  const move = (next: PointerEvent): void => setWidth(startWidth + next.clientX - startX);
  const stop = (): void => {
    dragging.value = false;
    window.removeEventListener("pointermove", move);
    window.removeEventListener("pointerup", stop);
  };
  window.addEventListener("pointermove", move);
  window.addEventListener("pointerup", stop, { once: true });
}

function keyResize(event: KeyboardEvent): void {
  if (collapsed.value) return;
  const step = event.shiftKey ? 32 : 8;
  if (event.key === "ArrowLeft") { event.preventDefault(); setWidth(width.value - step); }
  if (event.key === "ArrowRight") { event.preventDefault(); setWidth(width.value + step); }
  if (event.key === "Home") { event.preventDefault(); setWidth(220); }
  if (event.key === "End") { event.preventDefault(); setWidth(380); }
}

function setWidth(value: number): void {
  width.value = Math.min(Math.max(Math.round(value), 220), 380);
  try { localStorage.setItem("hwlab.workbench.sessionSidebarWidth.v1", String(width.value)); } catch { /* ignore */ }
}

function readWidth(): number {
  try {
    const parsed = Number(localStorage.getItem("hwlab.workbench.sessionSidebarWidth.v1"));
    return Number.isFinite(parsed) ? Math.min(Math.max(Math.round(parsed), 220), 380) : 300;
  } catch {
    return 300;
  }
}

function toggleCollapsed(): void {
  collapsed.value = !collapsed.value;
  try { localStorage.setItem(COLLAPSED_STORAGE_KEY, collapsed.value ? "true" : "false"); } catch { /* ignore */ }
}

function readCollapsed(): boolean {
  try {
    return localStorage.getItem(COLLAPSED_STORAGE_KEY) === "true";
  } catch {
    return false;
  }
}

function formatSessionUpdatedTime(value: string | null | undefined): string {
  if (!value) return "未记录";
  const date = new Date(value);
  if (!Number.isFinite(date.getTime())) return value;
  const delta = Date.now() - date.getTime();
  if (delta < 60_000) return "刚刚";
  if (delta < 3_600_000) return `${Math.max(1, Math.round(delta / 60_000))} 分`;
  if (delta < 86_400_000) return `${Math.max(1, Math.round(delta / 3_600_000))} 时`;
  if (delta < 604_800_000) return `${Math.max(1, Math.round(delta / 86_400_000))} 天`;
  return formatDisplayDateTime(date, { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" });
}
</script>

<template>
  <aside class="session-rail" id="session-sidebar" :class="{ 'is-resizing': dragging, 'is-collapsed': collapsed }" :data-collapsed="collapsed" :style="railStyle">
    <div class="panel-header compact">
      <div v-if="!collapsed">
        <p class="page-eyebrow">Sessions</p>
        <h2>显式会话</h2>
      </div>
      <div class="session-rail-header-actions">
        <button v-if="!collapsed" id="session-detail-toggle" class="message-detail-button session-detail-button" type="button" aria-label="Session 详情" title="Session 详情" :disabled="showSessionListLoading || !activeTab" @click="detailOpen = true">!</button>
        <button v-if="!collapsed" id="session-create" class="btn btn-primary btn-sm" type="button" @click="workbench.createSession">新建</button>
        <button id="session-collapse-toggle" class="btn btn-secondary btn-sm session-collapse-toggle" type="button" :aria-label="collapsed ? '展开 Sessions' : '折叠 Sessions'" :title="collapsed ? '展开 Sessions' : '折叠 Sessions'" :aria-expanded="!collapsed" @click="toggleCollapsed">{{ collapsed ? '›' : '‹' }}</button>
      </div>
    </div>
    <div v-if="!collapsed" class="session-list" id="session-tabs" :data-loading="showSessionListLoading">
      <LoadingState v-if="showSessionListLoading" class="session-list-loading" label="加载中" />
      <template v-else>
        <button v-for="tab in workbench.sessionTabs" :key="tab.sessionId || tab.key" class="session-tab" :data-active="tab.active" :data-running="tab.running" :data-status="tab.status || undefined" :data-projection-health="tab.projectionHealth || undefined" :data-session-id="tab.sessionId || undefined" type="button" :title="tab.projectionDiagnosticText || tab.label || tab.sessionId || tab.key" @click="workbench.selectSession(tab)">
          <span class="session-tab-title">{{ tab.label || tab.sessionId }}</span>
          <span v-if="tab.projectionDiagnosticText" class="session-tab-diagnostic">状态更新异常</span>
          <time class="session-tab-time" :datetime="tab.updatedAt || tab.startedAt || undefined">{{ formatSessionUpdatedTime(tab.updatedAt || tab.startedAt) }}</time>
        </button>
        <p v-if="workbench.sessionTabs.length === 0" class="muted-box">没有 session。发送前必须显式新建或选择 session。</p>
        <div v-else class="session-list-footer">
          <button v-if="workbench.sessionListHasMore" id="session-load-more" class="btn btn-secondary btn-sm session-load-more" type="button" :disabled="workbench.sessionListLoadingMore" @click="workbench.loadMoreSessions">
            {{ workbench.sessionListLoadingMore ? '加载中' : '加载更多' }}
          </button>
          <p v-else id="session-list-complete" class="session-list-terminal">已显示全部 sessions</p>
          <p v-if="workbench.sessionListLoadMoreError" id="session-load-more-error" class="session-list-error">{{ workbench.sessionListLoadMoreError }}</p>
        </div>
      </template>
    </div>
    <div v-if="!collapsed" class="session-rail-actions">
      <button id="session-copy" class="btn btn-secondary btn-sm" type="button" :disabled="showSessionListLoading || !activeTab" @click="copyActive">复制</button>
      <button id="session-delete" class="btn btn-secondary btn-sm" type="button" :disabled="showSessionListLoading || !activeTab" @click="workbench.deleteCurrentSession">删除当前</button>
    </div>
    <div v-if="detailOpen && activeTab" class="workbench-dialog-backdrop" role="presentation" @click.self="detailOpen = false">
      <section id="session-detail-dialog" class="workbench-dialog" role="dialog" aria-modal="true" aria-labelledby="session-detail-title">
        <header>
          <div class="dialog-title-stack">
            <h2 id="session-detail-title">Session 详情</h2>
            <p>{{ activeTab.sessionId || '未选择' }}</p>
          </div>
          <button type="button" class="dialog-close" aria-label="关闭" @click="detailOpen = false">x</button>
        </header>
        <dl class="session-detail-grid">
          <div><dt>sessionId</dt><dd>{{ activeTab.sessionId || '-' }}</dd></div>
          <div><dt>threadId</dt><dd>{{ activeTab.threadId || '-' }}</dd></div>
          <div><dt>lastTraceId</dt><dd>{{ activeTab.lastTraceId || '-' }}</dd></div>
          <div><dt>URL</dt><dd>{{ activeSessionUrl || '-' }}</dd></div>
          <div><dt>status</dt><dd>{{ activeTab.status || 'unknown' }}</dd></div>
          <div><dt>updatedAt</dt><dd>{{ activeTab.updatedAt || activeTab.startedAt || '未记录' }}</dd></div>
        </dl>
        <div class="session-detail-actions">
          <button id="session-detail-copy" class="btn btn-secondary btn-sm" type="button" @click="copyActive">复制</button>
          <span v-if="copied">已复制</span>
        </div>
      </section>
    </div>
    <div
      v-if="!collapsed"
      class="session-resize-handle"
      role="separator"
      tabindex="0"
      aria-label="调整 Session sidebar 宽度"
      aria-orientation="vertical"
      :aria-valuenow="width"
      aria-valuemin="220"
      aria-valuemax="380"
      @pointerdown="startResize"
      @keydown="keyResize"
    />
  </aside>
</template>
