import { mkdir, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { AppConfigService } from "../../apps/desktop/src/main/services/app-config.js";
import { ProjectChatTargetResolverService } from "../../apps/desktop/src/main/services/project-chat-target-resolver.js";
import { ProjectContextService } from "../../apps/desktop/src/main/services/project-context.js";
import { ProjectExecutionRouter } from "../../apps/desktop/src/main/services/project-execution-router.js";
import { ProjectIntentRouterService } from "../../apps/desktop/src/main/services/project-intent-router.js";
import { ProjectSkillRouterService } from "../../apps/desktop/src/main/services/project-skill-router.js";
import { ProjectStoreService } from "../../apps/desktop/src/main/services/project-store.js";
import type { SystemSummary } from "../../packages/shared-types/src/index.js";

function assert(condition: unknown, message: string): asserts condition {
  if (!condition) {
    throw new Error(message);
  }
}

async function writeSkill(workspaceRoot: string, skillId: string, body: string): Promise<void> {
  const skillPath = path.join(workspaceRoot, "skills", skillId, "SKILL.md");
  await mkdir(path.dirname(skillPath), { recursive: true });
  await writeFile(skillPath, body, "utf8");
}

async function main(): Promise<void> {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = path.resolve(__dirname, "..", "..");
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "project-routing-smoke", "result.json"));
  const tempRoot = path.dirname(resultPath);
  const userDataPath = path.join(tempRoot, "user-data");

  await rm(tempRoot, { recursive: true, force: true });
  await mkdir(userDataPath, { recursive: true });

  const configService = new AppConfigService(userDataPath);
  await configService.load();

  const projectStore = new ProjectStoreService(configService);
  await projectStore.initialize();
  const workspaceRoot = await projectStore.getWorkspaceRoot();

  await writeSkill(workspaceRoot, "xiaohongshu-pipeline", `---
name: xiaohongshu-pipeline
description: xiaohongshu end to end publish skill
---
`);
  await writeSkill(workspaceRoot, "xiaohongshu-writer", `---
name: xiaohongshu-writer
description: xiaohongshu publish draft skill
---
`);
  await writeSkill(workspaceRoot, "xiaohongshu-publisher", `---
name: xiaohongshu-publisher
description: xiaohongshu publish draft skill
---
`);
  await writeSkill(workspaceRoot, "douyin-script-writer", `---
name: douyin-script-writer
description: douyin script writing skill
---
`);

  const xiaohongshu = await projectStore.upsertProject({
    id: "xiaohongshu-workspace",
    name: "Xiaohongshu Workspace",
    description: "\u5c0f\u7ea2\u4e66\u7f8e\u5986\u53d1\u5e16\u9879\u76ee",
    boundSkillIds: ["xiaohongshu-pipeline", "xiaohongshu-writer", "xiaohongshu-publisher"],
    defaultEntry: {
      id: "workspace-entry",
      type: "workspace-entry",
      capabilities: ["publish", "workflow"],
      intentAliases: ["\u5c0f\u7ea2\u4e66", "\u53d1\u5e16", "\u53d1\u5e03"]
    },
    entries: [
      {
        id: "workspace-entry",
        type: "workspace-entry",
        capabilities: ["publish", "workflow"],
        intentAliases: ["\u5c0f\u7ea2\u4e66", "\u53d1\u5e16", "\u53d1\u5e03"]
      },
      {
        id: "xiaohongshu-pipeline",
        type: "skill",
        capabilities: ["publish", "workflow"],
        intentAliases: ["\u5c0f\u7ea2\u4e66", "\u53d1\u5e16", "\u53d1\u5e03"]
      },
      {
        id: "xiaohongshu-writer",
        type: "skill",
        capabilities: ["write", "draft"],
        intentAliases: ["\u6587\u6848", "\u7b14\u8bb0", "\u8349\u7a3f"]
      },
      {
        id: "xiaohongshu-publisher",
        type: "skill",
        capabilities: ["publish"],
        intentAliases: ["\u53d1\u5e03", "\u53d1\u5e16"]
      }
    ],
    ready: true
  });
  const douyin = await projectStore.upsertProject({
    id: "douyin-workspace",
    name: "Douyin Workspace",
    description: "\u6296\u97f3\u526a\u8f91\u811a\u672c\u9879\u76ee",
    boundSkillIds: ["douyin-script-writer"],
    ready: true
  });

  const intentRouter = new ProjectIntentRouterService(projectStore);
  const skillRouter = new ProjectSkillRouterService(projectStore);
  const projectContextService = new ProjectContextService(projectStore);
  const systemSummary: SystemSummary = {
    appName: "千匠问天",
    appVersion: "0.1.0-smoke",
    isPackaged: false,
    platform: process.platform,
    arch: process.arch,
    appPath: path.join(repoRoot, "apps", "desktop"),
    resourcesPath: path.join(repoRoot, "apps", "desktop"),
    userDataPath,
    logsPath: path.join(tempRoot, "logs")
  };
  const projectExecutionRouter = new ProjectExecutionRouter(systemSummary);
  const chatTargetResolver = new ProjectChatTargetResolverService(projectStore, intentRouter);

  await projectStore.setActiveProject(douyin.id);
  const seedSession = await projectStore.createSession("Douyin Session", douyin.id);
  const homeSession = await projectStore.createSession("Home Session", "home-chat");

  const publishPrompt = "\u53d1\u4e00\u4e2a\u7f8e\u5986\u7c7b\u7684\u5c0f\u7ea2\u4e66\u5e16\u5b50";
  const writePrompt = "\u5e2e\u6211\u5199\u4e00\u4e2a\u5c0f\u7ea2\u4e66\u62a4\u80a4\u6587\u6848";
  const publishExistingPrompt = "\u628a\u8fd9\u4e2a markdown \u8349\u7a3f\u53d1\u5e03\u5230\u5c0f\u7ea2\u4e66";

  const projectRoute = await intentRouter.resolve(publishPrompt, douyin.id);
  assert(projectRoute?.projectId === xiaohongshu.id, "Default chat project routing did not choose the Xiaohongshu workspace.");

  const preservedTarget = await chatTargetResolver.resolve(seedSession.id, publishPrompt, null);
  assert(!preservedTarget.autoRouted, "Chat target resolver should not auto-route requests that start inside a non-home project session.");
  assert(preservedTarget.sessionState.projectId === douyin.id, "Chat target resolver should preserve the original non-home project session.");
  assert(preservedTarget.sessionState.sessionId === seedSession.id, "Chat target resolver should reuse the original non-home project session.");

  const resolvedTarget = await chatTargetResolver.resolve(homeSession.id, publishPrompt, null);
  assert(!resolvedTarget.autoRouted, "Chat target resolver should keep the home chat request inside home-chat.");
  assert(resolvedTarget.previousProjectId === "home-chat", "Chat target resolver should report home-chat as the previous project.");
  assert(resolvedTarget.sessionState.projectId === "home-chat", "Chat target resolver should preserve the home-chat project for default chat requests.");
  assert(resolvedTarget.sessionState.sessionId === homeSession.id, "Chat target resolver should reuse the original home session for default chat requests.");

  const homeIntentSuggestion = await chatTargetResolver.resolveIntentSuggestion(publishPrompt, "home-chat");
  assert(homeIntentSuggestion?.projectId === xiaohongshu.id, "Home chat suggestion should recommend the Xiaohongshu workspace for Xiaohongshu publish prompts.");

  const sameProjectSuggestion = await chatTargetResolver.resolveIntentSuggestion(publishPrompt, xiaohongshu.id);
  assert(sameProjectSuggestion === null, "Suggestion lookup should not recommend switching when the current project already matches the resolved workspace.");

  const ambiguousPrompt = "帮我看一下这周的工作安排并整理成表格";
  const ambiguousSuggestion = await chatTargetResolver.resolveIntentSuggestion(ambiguousPrompt, "home-chat");
  assert(ambiguousSuggestion === null, "Home chat suggestion should stay silent for generic non-platform prompts.");

  const pipelineRoute = await skillRouter.resolve(xiaohongshu.id, publishPrompt);
  assert(pipelineRoute?.skillId === "xiaohongshu-pipeline", "Skill router did not choose the Xiaohongshu pipeline skill for the publish-style request.");

  const writerRoute = await skillRouter.resolve(xiaohongshu.id, writePrompt);
  assert(writerRoute?.skillId === "xiaohongshu-writer", "Skill router did not choose the Xiaohongshu writer skill for the writing-style request.");

  const publisherRoute = await skillRouter.resolve(xiaohongshu.id, publishExistingPrompt);
  assert(publisherRoute?.skillId === "xiaohongshu-publisher", "Skill router did not choose the Xiaohongshu publisher skill for the existing-draft publish request.");

  const xiaohongshuProjectRoot = await projectStore.getProjectRoot(xiaohongshu.id);
  await mkdir(path.join(xiaohongshuProjectRoot, "plugin"), { recursive: true });
  await writeFile(path.join(xiaohongshuProjectRoot, "plugin", "openclaw.plugin.json"), JSON.stringify({
    id: "xiaohongshu-plugin",
    name: "Xiaohongshu Plugin"
  }, null, 2), "utf8");
  const xiaohongshuSession = await projectStore.createSession("Xiaohongshu Session", xiaohongshu.id);
  const xiaohongshuSnapshot = await projectContextService.getSnapshot(xiaohongshu.id);
  const workspaceEntryDecision = await projectExecutionRouter.decide({
    sessionId: xiaohongshuSession.id,
    projectId: xiaohongshu.id,
    projectRoot: xiaohongshuProjectRoot,
    userPrompt: publishPrompt,
    context: xiaohongshuSnapshot,
    selectedSkillId: "xiaohongshu-writer",
    projectConfig: await projectStore.getProjectPackageConfig(xiaohongshu.id)
  });
  assert(workspaceEntryDecision.kind === "workspace-entry", "Execution router did not prefer workspace-entry for publish intent when a skill was already selected.");

  const legacyWorkspaceEntryDecision = await projectExecutionRouter.decide({
    sessionId: resolvedTarget.sessionState.sessionId,
    projectId: xiaohongshu.id,
    projectRoot: xiaohongshuProjectRoot,
    userPrompt: publishPrompt,
    context: xiaohongshuSnapshot,
    selectedSkillId: "xiaohongshu-writer",
    projectConfig: null
  });
  assert(legacyWorkspaceEntryDecision.kind === "workspace-entry", "Execution router did not detect the legacy plugin workspace-entry for publish intent.");

  const stickySkillDecision = await projectExecutionRouter.decide({
    sessionId: resolvedTarget.sessionState.sessionId,
    projectId: xiaohongshu.id,
    projectRoot: xiaohongshuProjectRoot,
    userPrompt: writePrompt,
    context: xiaohongshuSnapshot,
    selectedSkillId: "xiaohongshu-writer",
    projectConfig: await projectStore.getProjectPackageConfig(xiaohongshu.id)
  });
  assert(stickySkillDecision.kind === "skill", "Execution router should preserve the selected skill for non-publish Xiaohongshu prompts.");

  const summary = {
    ok: true,
    workspaceRoot,
    publishPrompt,
    writePrompt,
    publishExistingPrompt,
    initialProjectId: douyin.id,
    routedProjectId: projectRoute?.projectId ?? null,
    routedProjectReason: projectRoute?.reason ?? null,
    preservedSessionId: preservedTarget.sessionState.sessionId,
    preservedSessionProjectId: preservedTarget.sessionState.projectId,
    routedSessionId: resolvedTarget.sessionState.sessionId,
    routedSessionProjectId: resolvedTarget.sessionState.projectId,
    homeSuggestionProjectId: homeIntentSuggestion?.projectId ?? null,
    homeSuggestionReason: homeIntentSuggestion?.reason ?? null,
    sameProjectSuggestionSuppressed: sameProjectSuggestion === null,
    ambiguousSuggestionSuppressed: ambiguousSuggestion === null,
    pipelineSkillId: pipelineRoute?.skillId ?? null,
    pipelineRouteReason: pipelineRoute?.reason ?? null,
    writerSkillId: writerRoute?.skillId ?? null,
    publisherSkillId: publisherRoute?.skillId ?? null,
    publishDecisionKind: workspaceEntryDecision.kind,
    publishDecisionReason: workspaceEntryDecision.kind === "workspace-entry" ? workspaceEntryDecision.reason : null,
    legacyPublishDecisionKind: legacyWorkspaceEntryDecision.kind,
    legacyPublishDecisionReason: legacyWorkspaceEntryDecision.kind === "workspace-entry" ? legacyWorkspaceEntryDecision.reason : null,
    writeDecisionKind: stickySkillDecision.kind
  };

  await mkdir(path.dirname(resultPath), { recursive: true });
  await writeFile(resultPath, JSON.stringify(summary, null, 2), "utf8");
  console.log(JSON.stringify(summary, null, 2));
}

main().catch(async (error) => {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = path.resolve(__dirname, "..", "..");
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "project-routing-smoke", "result.json"));
  const failure = {
    ok: false,
    error: error instanceof Error ? error.stack ?? error.message : String(error)
  };
  await mkdir(path.dirname(resultPath), { recursive: true });
  await writeFile(resultPath, JSON.stringify(failure, null, 2), "utf8");
  console.error(failure.error);
  process.exitCode = 1;
});
