import test from "node:test"
import assert from "node:assert/strict"

import { refreshProjectContextAfterExecution } from "../src/main/services/project-context-lifecycle.ts"

function createHarness(options: {
  snapshotId?: string
  existingSnapshotId?: string | null
  refreshError?: Error
} = {}) {
  const calls: string[] = []
  const snapshotId = options.snapshotId ?? "snapshot-new"
  const existingSnapshotId = options.existingSnapshotId ?? null
  const refreshError = options.refreshError

  const projectContextService = {
    invalidateSnapshot(projectId: string) {
      calls.push(`invalidate:${projectId}`)
    },
    async refreshSnapshot(projectId: string) {
      calls.push(`refresh:${projectId}`)
      if (refreshError) {
        throw refreshError
      }
      return { snapshotId }
    }
  }

  const projectStore = {
    async getSessionState(sessionId: string) {
      calls.push(`get-session:${sessionId}`)
      return { contextSnapshotId: existingSnapshotId }
    },
    async bindSessionContextSnapshot(sessionId: string, nextSnapshotId: string) {
      calls.push(`bind-session:${sessionId}:${nextSnapshotId}`)
    }
  }

  return { calls, projectContextService, projectStore }
}

test("refreshes project context without reading session state when sessionId is omitted", async () => {
  const { calls, projectContextService, projectStore } = createHarness()

  await refreshProjectContextAfterExecution({
    projectId: "project-1",
    projectContextService,
    projectStore
  })

  assert.deepEqual(calls, [
    "invalidate:project-1",
    "refresh:project-1"
  ])
})

test("binds the refreshed snapshot to a provided session", async () => {
  const { calls, projectContextService, projectStore } = createHarness({
    snapshotId: "snapshot-new",
    existingSnapshotId: "snapshot-old"
  })

  await refreshProjectContextAfterExecution({
    sessionId: "project:project-1",
    projectId: "project-1",
    projectContextService,
    projectStore
  })

  assert.deepEqual(calls, [
    "invalidate:project-1",
    "refresh:project-1",
    "get-session:project:project-1",
    "bind-session:project:project-1:snapshot-new"
  ])
})

test("invalidates again and does not throw when refresh fails", async () => {
  const { calls, projectContextService, projectStore } = createHarness({
    refreshError: new Error("refresh failed")
  })

  await refreshProjectContextAfterExecution({
    projectId: "project-1",
    projectContextService,
    projectStore
  })

  assert.deepEqual(calls, [
    "invalidate:project-1",
    "refresh:project-1",
    "invalidate:project-1"
  ])
})
