import test from "node:test"
import assert from "node:assert/strict"
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"
import { tmpdir } from "node:os"
import path from "node:path"

import {
  collectWorkspaceExecutionArtifacts,
  createWorkspaceArtifactSnapshot
} from "../src/main/services/project-workspace-executor.ts"

async function withProjectRoot<T>(run: (projectRoot: string) => Promise<T>) {
  const projectRoot = await mkdtemp(path.join(tmpdir(), "qjc-workspace-artifacts-"))
  try {
    return await run(projectRoot)
  } finally {
    await rm(projectRoot, { recursive: true, force: true })
  }
}

test("detects new supported documents and summarizes markdown content", async () => {
  await withProjectRoot(async (projectRoot) => {
    const before = await createWorkspaceArtifactSnapshot(projectRoot)
    await writeFile(path.join(projectRoot, "result.md"), "这是本次产物摘要内容，用于工作台展示。".repeat(6), "utf8")

    const artifacts = await collectWorkspaceExecutionArtifacts({
      projectRoot,
      beforeSnapshot: before,
      assistantSummary: "assistant fallback"
    })

    assert.equal(artifacts.length, 1)
    assert.equal(artifacts[0]?.name, "result.md")
    assert.equal(artifacts[0]?.kind, "文档")
    assert.equal(artifacts[0]?.path, path.join(projectRoot, "result.md"))
    assert.equal(artifacts[0]?.url, path.join(projectRoot, "result.md"))
    assert.match(artifacts[0]?.summary ?? "", /^这是本次产物摘要内容/)
    assert.ok(artifacts[0]?.producedAt)
  })
})

test("detects modified files and ignores unsupported or excluded paths", async () => {
  await withProjectRoot(async (projectRoot) => {
    await writeFile(path.join(projectRoot, "existing.txt"), "before", "utf8")
    const before = await createWorkspaceArtifactSnapshot(projectRoot)

    await new Promise((resolve) => setTimeout(resolve, 20))
    await writeFile(path.join(projectRoot, "existing.txt"), "after", "utf8")
    await writeFile(path.join(projectRoot, "scratch.tmp"), "ignore", "utf8")
    await mkdir(path.join(projectRoot, "node_modules"), { recursive: true })
    await writeFile(path.join(projectRoot, "node_modules", "package.md"), "ignore", "utf8")
    await mkdir(path.join(projectRoot, "memory", "workspace-runner"), { recursive: true })
    await writeFile(path.join(projectRoot, "memory", "workspace-runner", "trace.md"), "ignore", "utf8")

    const artifacts = await collectWorkspaceExecutionArtifacts({
      projectRoot,
      beforeSnapshot: before,
      assistantSummary: "assistant fallback"
    })

    assert.deepEqual(artifacts.map((artifact) => artifact.name), ["existing.txt"])
    assert.equal(artifacts[0]?.kind, "文档")
  })
})

test("infers image video and spreadsheet artifact kinds", async () => {
  await withProjectRoot(async (projectRoot) => {
    const before = await createWorkspaceArtifactSnapshot(projectRoot)
    await writeFile(path.join(projectRoot, "cover.png"), "image", "utf8")
    await writeFile(path.join(projectRoot, "clip.mp4"), "video", "utf8")
    await writeFile(path.join(projectRoot, "data.xlsx"), "sheet", "utf8")

    const artifacts = await collectWorkspaceExecutionArtifacts({
      projectRoot,
      beforeSnapshot: before,
      assistantSummary: "assistant fallback"
    })

    assert.deepEqual(
      Object.fromEntries(artifacts.map((artifact) => [artifact.name, artifact.kind])),
      {
        "clip.mp4": "视频",
        "cover.png": "图片",
        "data.xlsx": "表格"
      }
    )
  })
})

test("uses full relative path identity for artifact ids", async () => {
  await withProjectRoot(async (projectRoot) => {
    const before = await createWorkspaceArtifactSnapshot(projectRoot)
    const sharedPrefix = "aaaaaaaaaaaaaaaaaaaaaaaa"
    await mkdir(path.join(projectRoot, sharedPrefix), { recursive: true })
    await writeFile(path.join(projectRoot, sharedPrefix, "one.md"), "one", "utf8")
    await writeFile(path.join(projectRoot, sharedPrefix, "two.md"), "two", "utf8")

    const artifacts = await collectWorkspaceExecutionArtifacts({
      projectRoot,
      beforeSnapshot: before,
      assistantSummary: "assistant fallback"
    })

    assert.deepEqual(artifacts.map((artifact) => artifact.name), ["one.md", "two.md"])
    assert.equal(new Set(artifacts.map((artifact) => artifact.id)).size, 2)
  })
})
