import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { MsgContext } from "../../auto-reply/templating.js";
import type { ChannelPlugin } from "../../channels/plugins/types.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
import {
  createChannelTestPluginBase,
  createTestRegistry,
} from "../../test-utils/channel-plugins.js";
import { normalizeExplicitSessionKey } from "./explicit-session-key-normalization.js";

function makeCtx(overrides: Partial<MsgContext>): MsgContext {
  return {
    Body: "",
    From: "",
    To: "",
    ...overrides,
  } as MsgContext;
}

beforeEach(() => {
  const discordPlugin: ChannelPlugin = {
    ...createChannelTestPluginBase({
      id: "discord",
      label: "Discord",
      docsPath: "/channels/discord",
    }),
    messaging: {
      normalizeExplicitSessionKey: ({ sessionKey, ctx }) => {
        const normalizedChatType = ctx.ChatType?.trim().toLowerCase();
        let normalized = sessionKey.trim().toLowerCase();
        if (normalizedChatType !== "direct" && normalizedChatType !== "dm") {
          return normalized;
        }
        normalized = normalized.replace(/^(discord:)dm:/, "$1direct:");
        normalized = normalized.replace(/^(agent:[^:]+:discord:)dm:/, "$1direct:");
        const match = normalized.match(/^((?:agent:[^:]+:)?)discord:channel:([^:]+)$/);
        if (!match) {
          return normalized;
        }
        const from = (ctx.From ?? "").trim().toLowerCase();
        const senderId = (ctx.SenderId ?? "").trim().toLowerCase();
        const fromDiscordId =
          from.startsWith("discord:") && !from.includes(":channel:") && !from.includes(":group:")
            ? from.slice("discord:".length)
            : "";
        const directId = senderId || fromDiscordId;
        return directId && directId === match[2]
          ? `${match[1]}discord:direct:${match[2]}`
          : normalized;
      },
    },
  };
  setActivePluginRegistry(
    createTestRegistry([
      {
        pluginId: "discord",
        plugin: discordPlugin,
        source: "test",
      },
    ]),
  );
});

afterEach(() => {
  resetPluginRuntimeStateForTest();
});

describe("normalizeExplicitSessionKey", () => {
  it("dispatches discord keys through the provider normalizer", () => {
    expect(
      normalizeExplicitSessionKey(
        "agent:fina:discord:channel:123456",
        makeCtx({
          Surface: "discord",
          ChatType: "direct",
          From: "discord:123456",
          SenderId: "123456",
        }),
      ),
    ).toBe("agent:fina:discord:direct:123456");
  });

  it("infers the provider from From when explicit provider fields are absent", () => {
    expect(
      normalizeExplicitSessionKey(
        "discord:dm:123456",
        makeCtx({
          ChatType: "direct",
          From: "discord:123456",
          SenderId: "123456",
        }),
      ),
    ).toBe("discord:direct:123456");
  });

  it("uses Provider when Surface is absent", () => {
    expect(
      normalizeExplicitSessionKey(
        "agent:fina:discord:dm:123456",
        makeCtx({
          Provider: "Discord",
          ChatType: "direct",
          SenderId: "123456",
        }),
      ),
    ).toBe("agent:fina:discord:direct:123456");
  });

  it("lowercases and passes through unknown providers unchanged", () => {
    expect(
      normalizeExplicitSessionKey(
        "Agent:Fina:Slack:DM:ABC",
        makeCtx({
          Surface: "slack",
          From: "slack:U123",
        }),
      ),
    ).toBe("agent:fina:slack:dm:abc");
  });
});
