import assert from "node:assert/strict";
import {
  LEGACY_PLANNER_SYSTEM_PROMPT,
  PLANNER_ASSISTANT_SEED,
} from "../ena-planner/ena-planner-presets.js";
import {
  createDefaultTaskProfiles,
  ensureTaskProfiles,
  getActiveTaskProfile,
  migrateLegacyProfileRegexToGlobal,
  migrateLegacyTaskProfiles,
  migratePerTaskRegexToGlobal,
  normalizeTaskProfile,
} from "../prompting/prompt-profiles.js";

const legacySettings = {
  extractPrompt: "旧提取提示",
  recallPrompt: "旧召回提示",
  compressPrompt: "",
  synopsisPrompt: "",
  reflectionPrompt: "",
  consolidationPrompt: "",
};

const migrated = migrateLegacyTaskProfiles(legacySettings);
assert.equal(migrated.taskProfilesVersion, 3);
assert.ok(migrated.taskProfiles);
assert.ok(migrated.taskProfiles.extract);
assert.ok(migrated.taskProfiles.recall);
assert.ok(migrated.taskProfiles.planner);

const extractProfile = getActiveTaskProfile(
  {
    ...legacySettings,
    taskProfiles: migrated.taskProfiles,
  },
  "extract",
);
assert.equal(extractProfile.taskType, "extract");
assert.equal(extractProfile.id, "default");
assert.ok(Array.isArray(extractProfile.blocks));
assert.equal(extractProfile.blocks.length, 16);
assert.deepEqual(
  extractProfile.blocks.map((block) => block.name),
  [
    "抬头",
    "角色定义",
    "身份确认",
    "角色描述",
    "用户设定",
    "世界书前块",
    "世界书后块",
    "图统计",
    "Schema",
    "活跃总结",
    "故事时间",
    "当前范围",
    "最近消息",
    "信息确认",
    "输出格式",
    "行为规则",
  ],
);
assert.deepEqual(
  extractProfile.blocks.map((block) => block.type),
  [
    "custom",
    "custom",
    "custom",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "builtin",
    "custom",
    "custom",
    "custom",
  ],
);
assert.deepEqual(
  extractProfile.blocks.map((block) => block.role),
  [
    "system",
    "system",
    "assistant",
    "system",
    "system",
    "system",
    "system",
    "system",
    "system",
    "system",
    "system",
    "system",
    "system",
    "assistant",
    "user",
    "user",
  ],
);
assert.equal(
  extractProfile.metadata.legacyPromptField,
  "extractPrompt",
);
assert.equal(
  extractProfile.metadata.legacyPromptSnapshot,
  "旧提取提示",
);

const defaults = createDefaultTaskProfiles();
assert.ok(defaults.extract.profiles.length > 0);
assert.ok(defaults.recall.profiles.length > 0);
assert.ok(defaults.compress.profiles.length > 0);
assert.ok(defaults.synopsis.profiles.length > 0);
assert.ok(defaults.reflection.profiles.length > 0);
assert.deepEqual(
  defaults.recall.profiles[0].blocks.map((block) => block.sourceKey || block.id),
  [
    "default-heading",
    "default-role",
    "default-identity-ack",
    "charDescription",
    "userPersona",
    "worldInfoBefore",
    "worldInfoAfter",
    "graphStats",
    "sceneOwnerCandidates",
    "candidateNodes",
    "recentMessages",
    "userMessage",
    "default-info-ack",
    "default-format",
    "default-rules",
  ],
);
assert.deepEqual(
  defaults.synopsis.profiles[0].blocks.map((block) => block.sourceKey || block.id),
  [
    "default-heading",
    "default-role",
    "default-identity-ack",
    "charDescription",
    "userPersona",
    "worldInfoBefore",
    "worldInfoAfter",
    "graphStats",
    "candidateText",
    "currentRange",
    "recentMessages",
    "default-info-ack",
    "default-format",
    "default-rules",
  ],
);
assert.ok(defaults.summary_rollup.profiles.length > 0);
assert.ok(defaults.planner.profiles.length > 0);
assert.deepEqual(
  defaults.planner.profiles[0].blocks.map((block) => block.sourceKey || block.id),
  [
    "planner-default-heading",
    "planner-default-role",
    "planner-default-identity-ack",
    "plannerCharacterCard",
    "plannerWorldbook",
    "plannerMemory",
    "plannerPreviousPlots",
    "plannerRecentChat",
    "plannerUserInput",
    "planner-default-info-ack",
    "planner-default-format",
    "planner-default-rules",
    "planner-default-assistant-seed",
  ],
);
assert.equal(defaults.planner.profiles[0].generation.stream, true);
assert.equal(defaults.planner.profiles[0].generation.temperature, 1);

const currentDefaultPlanner = defaults.planner.profiles[0];
const cloneValue = (value) => JSON.parse(JSON.stringify(value));

function buildLegacyPlannerDefaultLikeBlocks() {
  return [
    {
      id: "planner-legacy-default-system",
      name: "Ena Planner System",
      type: "custom",
      enabled: true,
      role: "system",
      sourceKey: "",
      sourceField: "",
      content: LEGACY_PLANNER_SYSTEM_PROMPT,
      injectionMode: "relative",
      order: 0,
    },
    {
      id: "planner-legacy-default-char",
      name: "角色卡",
      type: "builtin",
      enabled: true,
      role: "system",
      sourceKey: "plannerCharacterCard",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 1,
    },
    {
      id: "planner-legacy-default-worldbook",
      name: "世界书",
      type: "builtin",
      enabled: true,
      role: "system",
      sourceKey: "plannerWorldbook",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 2,
    },
    {
      id: "planner-legacy-default-recent-chat",
      name: "最近聊天",
      type: "builtin",
      enabled: true,
      role: "system",
      sourceKey: "plannerRecentChat",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 3,
    },
    {
      id: "planner-legacy-default-memory",
      name: "BME 记忆",
      type: "builtin",
      enabled: true,
      role: "system",
      sourceKey: "plannerMemory",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 4,
    },
    {
      id: "planner-legacy-default-previous-plots",
      name: "历史 plot",
      type: "builtin",
      enabled: true,
      role: "system",
      sourceKey: "plannerPreviousPlots",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 5,
    },
    {
      id: "planner-legacy-default-user-input",
      name: "玩家输入",
      type: "builtin",
      enabled: true,
      role: "user",
      sourceKey: "plannerUserInput",
      sourceField: "",
      content: "",
      injectionMode: "relative",
      order: 6,
    },
    {
      id: "planner-legacy-default-seed",
      name: "Assistant Seed",
      type: "custom",
      enabled: true,
      role: "assistant",
      sourceKey: "",
      sourceField: "",
      content: PLANNER_ASSISTANT_SEED,
      injectionMode: "relative",
      order: 7,
    },
  ];
}

function createLegacyPlannerDefaultLikeProfile(overrides = {}) {
  return {
    id: "planner-legacy-default-like",
    taskType: "planner",
    builtin: false,
    name: "ENA 当前配置",
    promptMode: "block-based",
    enabled: true,
    updatedAt: "2026-04-23T00:00:00.000Z",
    blocks: buildLegacyPlannerDefaultLikeBlocks(),
    generation: cloneValue(currentDefaultPlanner.generation),
    metadata: {
      migratedFromLegacy: true,
      enaLegacySource: "legacy-working-copy",
    },
    ...overrides,
    blocks: Array.isArray(overrides.blocks)
      ? overrides.blocks
      : buildLegacyPlannerDefaultLikeBlocks(),
    generation: {
      ...cloneValue(currentDefaultPlanner.generation),
      ...(overrides.generation || {}),
    },
    metadata: {
      migratedFromLegacy: true,
      enaLegacySource: "legacy-working-copy",
      ...(overrides.metadata || {}),
    },
  };
}

const legacyPlannerDefaultLikeProfile = createLegacyPlannerDefaultLikeProfile();
const alignedLegacyPlannerDefaults = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    planner: {
      activeProfileId: legacyPlannerDefaultLikeProfile.id,
      profiles: [cloneValue(currentDefaultPlanner), legacyPlannerDefaultLikeProfile],
    },
  },
});
const alignedLegacyPlannerProfile = alignedLegacyPlannerDefaults.planner.profiles.find(
  (profile) => profile.id === legacyPlannerDefaultLikeProfile.id,
);
assert.equal(alignedLegacyPlannerDefaults.planner.activeProfileId, "default");
assert.deepEqual(
  alignedLegacyPlannerProfile.blocks.map((block) => block.sourceKey || block.id),
  currentDefaultPlanner.blocks.map((block) => block.sourceKey || block.id),
);
assert.equal(alignedLegacyPlannerProfile.metadata.plannerLegacyDefaultAligned, true);

const legacyPlannerCustomGenerationProfile = createLegacyPlannerDefaultLikeProfile({
  id: "planner-legacy-custom-generation",
  generation: {
    temperature: 0.7,
  },
});
const alignedLegacyPlannerCustomGeneration = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    planner: {
      activeProfileId: legacyPlannerCustomGenerationProfile.id,
      profiles: [
        cloneValue(currentDefaultPlanner),
        legacyPlannerCustomGenerationProfile,
      ],
    },
  },
});
const alignedLegacyPlannerCustomGenerationProfile =
  alignedLegacyPlannerCustomGeneration.planner.profiles.find(
    (profile) => profile.id === legacyPlannerCustomGenerationProfile.id,
  );
assert.equal(
  alignedLegacyPlannerCustomGeneration.planner.activeProfileId,
  legacyPlannerCustomGenerationProfile.id,
);
assert.deepEqual(
  alignedLegacyPlannerCustomGenerationProfile.blocks.map(
    (block) => block.sourceKey || block.id,
  ),
  currentDefaultPlanner.blocks.map((block) => block.sourceKey || block.id),
);
assert.equal(alignedLegacyPlannerCustomGenerationProfile.generation.temperature, 0.7);

const customizedLegacyPlannerBlocks = buildLegacyPlannerDefaultLikeBlocks();
customizedLegacyPlannerBlocks[0].content = `${customizedLegacyPlannerBlocks[0].content}\n\n自定义补充`; 
const customizedLegacyPlannerProfile = createLegacyPlannerDefaultLikeProfile({
  id: "planner-legacy-customized",
  blocks: customizedLegacyPlannerBlocks,
});
const preservedCustomizedLegacyPlanner = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    planner: {
      activeProfileId: customizedLegacyPlannerProfile.id,
      profiles: [cloneValue(currentDefaultPlanner), customizedLegacyPlannerProfile],
    },
  },
});
const preservedCustomizedLegacyPlannerProfile =
  preservedCustomizedLegacyPlanner.planner.profiles.find(
    (profile) => profile.id === customizedLegacyPlannerProfile.id,
  );
assert.equal(
  preservedCustomizedLegacyPlanner.planner.activeProfileId,
  customizedLegacyPlannerProfile.id,
);
assert.match(
  preservedCustomizedLegacyPlannerProfile.blocks[0].content,
  /自定义补充/,
);

const upgradedLegacyDefault = getActiveTaskProfile(
  {
    taskProfilesVersion: 1,
    taskProfiles: {
      extract: {
        activeProfileId: "default",
        profiles: [
          {
            id: "default",
            taskType: "extract",
            builtin: true,
            blocks: [
              {
                id: "default-role",
                name: "角色定义",
                type: "custom",
                role: "system",
                content: "保留我自己的角色定义",
                order: 0,
              },
              {
                id: "default-char-desc",
                name: "角色描述",
                type: "builtin",
                role: "system",
                sourceKey: "charDescription",
                order: 1,
              },
              {
                id: "default-user-persona",
                name: "用户设定",
                type: "builtin",
                role: "system",
                sourceKey: "userPersona",
                order: 2,
              },
              {
                id: "default-wi-before",
                name: "世界书前块",
                type: "builtin",
                role: "system",
                sourceKey: "worldInfoBefore",
                order: 3,
              },
              {
                id: "default-wi-after",
                name: "世界书后块",
                type: "builtin",
                role: "system",
                sourceKey: "worldInfoAfter",
                order: 4,
              },
              {
                id: "default-format",
                name: "输出格式",
                type: "custom",
                role: "system",
                content: "保留我自己的输出格式",
                order: 5,
              },
              {
                id: "default-rules",
                name: "行为规则",
                type: "custom",
                role: "system",
                content: "保留我自己的行为规则",
                order: 6,
              },
            ],
          },
        ],
      },
    },
  },
  "extract",
);
assert.equal(upgradedLegacyDefault.blocks.length, 16);
assert.equal(upgradedLegacyDefault.blocks[0].name, "抬头");
assert.match(upgradedLegacyDefault.blocks[0].content, /虚拟的世界/);
assert.equal(upgradedLegacyDefault.blocks[0].role, "system");
assert.equal(upgradedLegacyDefault.blocks[0].injectionMode, "relative");
assert.equal(upgradedLegacyDefault.blocks[1].content, "保留我自己的角色定义");
const upgradedIdentityAck = upgradedLegacyDefault.blocks.find(
  (block) => block.id === "default-identity-ack",
);
assert.ok(
  upgradedIdentityAck,
  "legacy upgrade should backfill default-identity-ack block",
);
assert.equal(upgradedIdentityAck.role, "assistant");
const upgradedInfoAck = upgradedLegacyDefault.blocks.find(
  (block) => block.id === "default-info-ack",
);
assert.ok(
  upgradedInfoAck,
  "legacy upgrade should backfill default-info-ack block",
);
assert.equal(upgradedInfoAck.role, "assistant");
assert.equal(upgradedLegacyDefault.blocks[14].id, "default-format");
assert.equal(upgradedLegacyDefault.blocks[15].id, "default-rules");
assert.equal(upgradedLegacyDefault.blocks[14].content, "保留我自己的输出格式");
assert.equal(upgradedLegacyDefault.blocks[15].content, "保留我自己的行为规则");
assert.equal(upgradedLegacyDefault.blocks[14].role, "user");
assert.equal(upgradedLegacyDefault.blocks[15].role, "user");

const currentDefaults = createDefaultTaskProfiles();
const currentDefaultExtract = currentDefaults.extract.profiles[0];

const staleBuiltinDefaults = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    extract: {
      activeProfileId: "default",
      profiles: [
        {
          ...currentDefaultExtract,
          updatedAt: "2000-01-01T00:00:00.000Z",
          blocks: currentDefaultExtract.blocks.map((block) =>
            block.id === "default-role"
              ? { ...block, content: "这是过期的默认角色定义" }
              : block,
          ),
          metadata: {
            ...(currentDefaultExtract.metadata || {}),
            defaultTemplateVersion:
              Number(currentDefaultExtract.metadata?.defaultTemplateVersion || 3),
            defaultTemplateUpdatedAt: "2000-01-01T00:00:00.000Z",
          },
        },
        {
          id: "extract-custom-1",
          taskType: "extract",
          builtin: false,
          name: "我的自定义预设",
          promptMode: "block-based",
          enabled: true,
          updatedAt: "2026-04-05T00:00:00.000Z",
          blocks: [
            {
              id: "custom-block-1",
              name: "自定义块",
              type: "custom",
              enabled: true,
              role: "system",
              sourceKey: "",
              sourceField: "",
              content: "保留我的自定义内容",
              injectionMode: "append",
              order: 0,
            },
          ],
          generation: { ...(currentDefaultExtract.generation || {}) },
          regex: {
            ...(currentDefaultExtract.regex || {}),
            localRules: [],
          },
          metadata: {
            note: "custom-profile-should-stay",
          },
        },
      ],
    },
  },
});
const refreshedDefaultExtract = staleBuiltinDefaults.extract.profiles.find(
  (profile) => profile.id === "default",
);
const preservedCustomExtract = staleBuiltinDefaults.extract.profiles.find(
  (profile) => profile.id === "extract-custom-1",
);

assert.ok(refreshedDefaultExtract);
assert.equal(
  refreshedDefaultExtract.blocks.find((block) => block.id === "default-role")
    ?.content,
  currentDefaultExtract.blocks.find((block) => block.id === "default-role")
    ?.content,
);
assert.equal(
  refreshedDefaultExtract.metadata.defaultTemplateUpdatedAt,
  currentDefaultExtract.metadata.defaultTemplateUpdatedAt,
);
assert.equal(
  refreshedDefaultExtract.metadata.defaultTemplateFingerprint,
  currentDefaultExtract.metadata.defaultTemplateFingerprint,
);
assert.match(
  refreshedDefaultExtract.blocks.find((block) => block.id === "default-format")
    ?.content || "",
  /cognitionUpdates/,
);
assert.ok(preservedCustomExtract);
assert.equal(
  preservedCustomExtract.blocks[0].content,
  "保留我的自定义内容",
);

const sameStampBuiltinDefault = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    extract: {
      activeProfileId: "default",
      profiles: [
        {
          ...currentDefaultExtract,
          blocks: currentDefaultExtract.blocks.map((block) =>
            block.id === "default-role"
              ? { ...block, content: "同版本下保留我的默认预设修改" }
              : block,
          ),
          metadata: {
            ...(currentDefaultExtract.metadata || {}),
          },
        },
      ],
    },
  },
});
const sameStampDefaultExtract = sameStampBuiltinDefault.extract.profiles.find(
  (profile) => profile.id === "default",
);
assert.equal(
  sameStampDefaultExtract.blocks.find((block) => block.id === "default-role")
    ?.content,
  "同版本下保留我的默认预设修改",
);

const sameTimestampButChangedTemplateDefaults = ensureTaskProfiles({
  taskProfilesVersion: 3,
  taskProfiles: {
    extract: {
      activeProfileId: "default",
      profiles: [
        {
          ...currentDefaultExtract,
          blocks: currentDefaultExtract.blocks.map((block) =>
            block.id === "default-role"
              ? { ...block, content: "老模板内容但时间戳没变" }
              : block,
          ),
          metadata: {
            ...(currentDefaultExtract.metadata || {}),
            defaultTemplateFingerprint: "fnv1a-deadbeef",
          },
        },
      ],
    },
  },
});
const fingerprintRefreshedDefault =
  sameTimestampButChangedTemplateDefaults.extract.profiles.find(
    (profile) => profile.id === "default",
  );
assert.equal(
  fingerprintRefreshedDefault.blocks.find(
    (block) => block.id === "default-role",
  )?.content,
  currentDefaultExtract.blocks.find((block) => block.id === "default-role")
    ?.content,
);

assert.deepEqual(
  upgradedLegacyDefault.blocks
    .slice(7, 13)
    .map((block) => block.sourceKey),
  [
    "graphStats",
    "schema",
    "activeSummaries",
    "storyTimeContext",
    "currentRange",
    "recentMessages",
  ],
);
assert.ok(
  upgradedLegacyDefault.blocks
    .slice(0, 2)
    .every((block) => block.role === "system"),
  "heading / role 头部块应保持 system 角色",
);
assert.equal(upgradedLegacyDefault.blocks[2].id, "default-identity-ack");
assert.equal(upgradedLegacyDefault.blocks[2].role, "assistant");
assert.ok(
  upgradedLegacyDefault.blocks
    .slice(3, 13)
    .every((block) => block.role === "system"),
  "参考材料与本轮输入块应为 system 角色",
);
assert.equal(upgradedLegacyDefault.blocks[13].id, "default-info-ack");
assert.equal(upgradedLegacyDefault.blocks[13].role, "assistant");

const legacyRegexSettings = {
  taskProfilesVersion: 3,
  taskProfiles: createDefaultTaskProfiles(),
};
legacyRegexSettings.taskProfiles.extract.activeProfileId = "default";
legacyRegexSettings.taskProfiles.extract.profiles.push(
  normalizeTaskProfile("extract", {
    id: "extract-legacy-regex",
    taskType: "extract",
    name: "旧正则副本",
    builtin: false,
    regex: {
      enabled: true,
      inheritStRegex: true,
      localRules: [
        {
          id: "legacy-rule-1",
          script_name: "隐藏规则",
          enabled: true,
          find_regex: "/SECRET/g",
          replace_string: "MASK",
        },
      ],
    },
  }),
);
const migratedLegacyRegex = migratePerTaskRegexToGlobal(legacyRegexSettings);
assert.equal(migratedLegacyRegex.changed, true);
assert.equal(migratedLegacyRegex.settings.globalTaskRegex.enabled, true);
assert.deepEqual(
  migratedLegacyRegex.settings.globalTaskRegex.localRules.map((rule) => rule.script_name),
  [
    "默认清理：thinking/analysis/reasoning",
    "默认清理：choice",
    "默认清理：UpdateVariable",
    "默认清理：status_current_variable",
    "默认清理：StatusPlaceHolderImpl",
    "隐藏规则",
  ],
);
assert.deepEqual(
  migratedLegacyRegex.settings.taskProfiles.extract.profiles.find(
    (profile) => profile.id === "extract-legacy-regex",
  )?.regex?.localRules || [],
  [],
);

const existingGlobalRegexSettings = {
  taskProfilesVersion: 3,
  globalTaskRegex: {
    enabled: true,
    inheritStRegex: true,
    sources: {
      global: true,
      preset: true,
      character: true,
    },
    stages: {
      "input.userMessage": true,
      "input.recentMessages": true,
    },
    localRules: [
      {
        id: "existing-global-rule",
        script_name: "现有通用规则",
        enabled: true,
        find_regex: "/GLOBAL/g",
        replace_string: "KEEP",
      },
    ],
  },
  taskProfiles: createDefaultTaskProfiles(),
};
existingGlobalRegexSettings.taskProfiles.extract.profiles.push(
  normalizeTaskProfile("extract", {
    id: "extract-legacy-extra",
    taskType: "extract",
    name: "旧规则补充",
    builtin: false,
    regex: {
      localRules: [
        {
          id: "legacy-extra-rule",
          script_name: "额外旧规则",
          enabled: true,
          find_regex: "/EXTRA/g",
          replace_string: "ADD",
        },
      ],
    },
  }),
);
const migratedWithExistingGlobal = migratePerTaskRegexToGlobal(
  existingGlobalRegexSettings,
);
assert.equal(migratedWithExistingGlobal.settings.globalTaskRegex.enabled, true);
assert.deepEqual(
  migratedWithExistingGlobal.settings.globalTaskRegex.localRules.map(
    (rule) => rule.script_name,
  ),
  ["现有通用规则", "额外旧规则"],
);

const importedLegacyProfileMigration = migrateLegacyProfileRegexToGlobal(
  {
    enabled: true,
    inheritStRegex: true,
    sources: {
      global: true,
      preset: true,
      character: true,
    },
    stages: {
      "input.userMessage": true,
      "input.recentMessages": true,
    },
    localRules: [],
  },
  {
    taskType: "extract",
    regex: {
      enabled: false,
      inheritStRegex: false,
      sources: {
        global: false,
        preset: false,
        character: false,
      },
      stages: {
        "input.userMessage": false,
      },
      localRules: [
        {
          id: "legacy-import-rule",
          script_name: "旧导入规则",
          enabled: true,
          find_regex: "/A/g",
          replace_string: "B",
        },
      ],
    },
  },
  {
    applyLegacyConfig: true,
  },
);
assert.equal(importedLegacyProfileMigration.appliedLegacyConfig, true);
assert.equal(importedLegacyProfileMigration.globalTaskRegex.enabled, false);
assert.equal(
  importedLegacyProfileMigration.globalTaskRegex.inheritStRegex,
  false,
);
assert.equal(
  importedLegacyProfileMigration.globalTaskRegex.sources.global,
  false,
);
assert.equal(
  importedLegacyProfileMigration.globalTaskRegex.stages["input.userMessage"],
  false,
);
assert.deepEqual(
  importedLegacyProfileMigration.globalTaskRegex.localRules.map(
    (rule) => rule.script_name,
  ),
  ["旧导入规则"],
);
assert.deepEqual(
  importedLegacyProfileMigration.profile?.regex || {},
  {},
);

console.log("task-profile-migration tests passed");
