import type {
  SessionQueueErrorCode,
  SessionQueueItem,
  SessionQueueStatus,
} from "#cli/core/session-meta";
import type { DimSdkStore } from "#cli/core/store";
import type { ComputedRef } from "vue";
import type { DimSdkSessionsApi } from "../../../keys";
import {
  defaultSessionUiMetadata,
  mergeSessionUiMetadata,
  normalizeSessionUiMetadata,
  SESSION_QUEUE_LIMIT,
} from "#cli/core/session-meta";
import { computed, getCurrentInstance, onBeforeUnmount } from "vue";
import { createDebouncedAsyncTask } from "../../../cli/utils/debounce";

export type SessionMetaMerged = ReturnType<typeof mergeSessionUiMetadata>;
export type SessionMetaPatch = Partial<SessionMetaMerged>;
export type UpdateSessionMeta = (
  patch: SessionMetaPatch,
  opts?: { bumpUpdatedAt?: boolean },
) => void;

export function useChatSessionMeta(
  opts: Readonly<{
    store: DimSdkStore;
    sessionsApi?: DimSdkSessionsApi;
  }>,
): Readonly<{
  currentSessionId: ComputedRef<string>;
  sessionMeta: ComputedRef<SessionMetaMerged | null>;
  queueItems: ComputedRef<readonly SessionQueueItem[]>;
  queueStatus: ComputedRef<SessionQueueStatus>;
  queueErrorCode: ComputedRef<SessionQueueErrorCode | null>;
  pinnedMessageIds: ComputedRef<readonly string[]>;
  applySessionMeta: (next: SessionMetaMerged) => void;
  updateSessionMeta: UpdateSessionMeta;
}> {
  const store = opts.store;
  const sessionsApi = opts.sessionsApi;

  const currentSessionId = computed(() => String(store.state.sessionId ?? "").trim());
  const sessionMeta = computed<SessionMetaMerged | null>(() => store.state.sessionMeta ?? null);
  const queueItems = computed(() => (sessionMeta.value?.queue ?? []) as SessionQueueItem[]);
  const queueStatus = computed(() => (sessionMeta.value?.status ?? "idle") as SessionQueueStatus);
  const queueErrorCode = computed(
    () => (sessionMeta.value?.lastErrorCode ?? null) as SessionQueueErrorCode | null,
  );
  const pinnedMessageIds = computed(() => {
    const list = sessionMeta.value?.pinnedMessageIds ?? [];
    return Array.isArray(list) ? list.map((id) => String(id ?? "").trim()).filter(Boolean) : [];
  });

  const persistSessionMeta = createDebouncedAsyncTask(async () => {
    if (!sessionsApi || typeof sessionsApi.updateMetadata !== "function") return;
    const sessionId = currentSessionId.value;
    if (!sessionId) return;
    const meta = sessionMeta.value ?? null;
    if (!meta) return;
    const normalized = normalizeSessionUiMetadata(meta);
    const payload = {
      queue: normalized.queue.slice(0, SESSION_QUEUE_LIMIT),
      queueLength: Number(normalized.queueLength ?? normalized.queue.length ?? 0) || 0,
      status: normalized.status ?? "idle",
      lastUpdatedAt: Number(normalized.lastUpdatedAt ?? 0) || 0,
      lastErrorCode: normalized.lastErrorCode ?? undefined,
      pinnedMessageIds: Array.isArray(normalized.pinnedMessageIds)
        ? normalized.pinnedMessageIds
        : [],
      titleSuggestedAt: normalized.titleSuggestedAt ?? undefined,
      reasoningDiagnosticsByTurn: normalized.reasoningDiagnosticsByTurn ?? {},
    };
    try {
      await sessionsApi.updateMetadata(sessionId, payload);
    } catch {
      // Session metadata persistence is best-effort only.
    }
  }, 180);
  if (getCurrentInstance()) {
    onBeforeUnmount(() => persistSessionMeta.cancel());
  }

  const applySessionMeta = (next: SessionMetaMerged) => {
    const target = store.state.sessionMeta;
    target.queue = [...next.queue];
    target.queueLength = next.queueLength;
    target.status = next.status;
    target.lastUpdatedAt = next.lastUpdatedAt;
    target.lastErrorCode = next.lastErrorCode ?? undefined;
    target.pinnedMessageIds = [...next.pinnedMessageIds];
    target.titleSuggestedAt = next.titleSuggestedAt ?? undefined;
    target.reasoningDiagnosticsByTurn = {
      ...next.reasoningDiagnosticsByTurn,
    };
    persistSessionMeta.schedule();
  };

  const updateSessionMeta: UpdateSessionMeta = (patch, opts) => {
    const base = mergeSessionUiMetadata(sessionMeta.value ?? defaultSessionUiMetadata(), {});
    const bump = opts?.bumpUpdatedAt !== false ? { lastUpdatedAt: Date.now() } : {};
    const merged = mergeSessionUiMetadata(base, { ...patch, ...bump });
    applySessionMeta(merged);
  };

  return {
    currentSessionId,
    sessionMeta,
    queueItems,
    queueStatus,
    queueErrorCode,
    pinnedMessageIds,
    applySessionMeta,
    updateSessionMeta,
  };
}
