import { describe, expect, it } from "vitest";

import type {
  PendingChatPromotion,
  PendingChatUnlock,
} from "@/lib/navigation/chat_unlock_session";
import { createChatPromotionState } from "@/stores/chat/helper/promotion";

import {
  resolveChatUnlockReturnUrl,
  resolveMessageUnlockRequest,
  resolvePendingUnlockDisplayMessageId,
  shouldResumePendingChatUnlock,
} from "../hooks/use-chat-unlock-coordinator";

const defaultScope = {
  defaultReturnUrl: "/chat",
  imageMessageId: null,
  imageReturnUrl: "/chat",
  promotion: null,
};

const promotionSession: PendingChatPromotion = {
  characterId: "elio",
  promotionType: "image",
  lockType: "image_paywall",
  clientLockId: "promotion-1",
  createdAt: 1,
};

describe("chat unlock coordinator", () => {
  it("creates a regular message unlock request with its remote id", () => {
    expect(
      resolveMessageUnlockRequest(
        {
          displayMessageId: "server:message-1:assistant",
          remoteMessageId: "message-1",
          kind: "private",
        },
        defaultScope,
      ),
    ).toEqual({
      displayMessageId: "server:message-1:assistant",
      messageId: "message-1",
      kind: "private",
      returnUrl: "/chat",
    });
  });

  it("returns to the active image overlay for its image unlock", () => {
    const imageScope = {
      ...defaultScope,
      imageMessageId: "image-1",
      imageReturnUrl: "/chat?image=image-1",
    };

    expect(
      resolveMessageUnlockRequest(
        {
          displayMessageId: "image-1",
          remoteMessageId: "image-1",
          kind: "image",
        },
        imageScope,
      ).returnUrl,
    ).toBe("/chat?image=image-1");
  });

  it("uses the promotion lock identity without sending a temporary remote id", () => {
    const promotion = createChatPromotionState(promotionSession);

    expect(
      resolveMessageUnlockRequest(
        {
          displayMessageId: "promotion:promotion-1",
          kind: "image",
        },
        { ...defaultScope, promotion },
      ),
    ).toEqual({
      displayMessageId: "promotion:promotion-1",
      kind: "image",
      lockType: "image_paywall",
      clientLockId: "promotion-1",
      promotion: promotionSession,
      returnUrl: "/chat",
    });
  });

  it("keeps the backend id after a promotion receives one", () => {
    const promotion = createChatPromotionState(
      promotionSession,
      "promotion-message-1",
    );

    expect(
      resolveMessageUnlockRequest(
        {
          displayMessageId: "promotion:promotion-1",
          remoteMessageId: "promotion-message-1",
          kind: "image",
        },
        { ...defaultScope, promotion },
      ).messageId,
    ).toBe("promotion-message-1");
  });

  it("resumes pending unlocks for the default chat return", () => {
    expect(
      shouldResumePendingChatUnlock(
        createPendingUnlock({
          displayMessageId: "message-1",
          messageId: "message-1",
          kind: "private",
          returnUrl: "/chat",
        }),
        defaultScope,
      ),
    ).toBe(true);
  });

  it("maps a legacy pending remote id to the current display identity", () => {
    const pending = createPendingUnlock({
      displayMessageId: "message-1",
      messageId: "message-1",
      kind: "private",
      returnUrl: "/chat",
    });

    expect(
      resolvePendingUnlockDisplayMessageId(
        pending,
        [
          {
            displayId: "server:message-1:user",
            remoteId: "message-1",
            content: "Question",
            isFromAI: false,
            date: "2026-07-20",
          },
          {
            displayId: "server:message-1:assistant",
            remoteId: "message-1",
            content: "Locked reply",
            isFromAI: true,
            date: "2026-07-20",
            locked: true,
            lockReason: "private_message",
          },
        ],
        null,
      ),
    ).toBe("server:message-1:assistant");
  });

  it("only resumes an image return when its message matches the overlay", () => {
    const imageScope = {
      defaultReturnUrl: "/chat",
      imageMessageId: "image-1",
      imageReturnUrl: "/chat?image=image-1",
    };
    const pending = createPendingUnlock({
      displayMessageId: "image-1",
      messageId: "image-1",
      kind: "image",
      returnUrl: "/chat?image=image-1",
    });

    expect(shouldResumePendingChatUnlock(pending, imageScope)).toBe(true);
    expect(
      shouldResumePendingChatUnlock(
        { ...pending, displayMessageId: "image-2", messageId: "image-2" },
        imageScope,
      ),
    ).toBe(false);
  });

  it("never routes a promotion unlock through the image overlay", () => {
    const promotion = createChatPromotionState(promotionSession);
    const imageMessageId = "promotion:promotion-1";
    const imageScope = {
      defaultReturnUrl: "/chat",
      imageMessageId,
      imageReturnUrl: `/chat?image=${imageMessageId}`,
    };

    expect(
      resolveMessageUnlockRequest(
        { displayMessageId: imageMessageId, kind: "image" },
        {
          ...imageScope,
          promotion,
        },
      ).returnUrl,
    ).toBe("/chat");
    expect(
      shouldResumePendingChatUnlock(
        {
          ...createPendingUnlock({
            displayMessageId: imageMessageId,
            kind: "image",
            returnUrl: imageScope.imageReturnUrl,
          }),
          lockType: promotionSession.lockType,
          clientLockId: promotionSession.clientLockId,
          promotion: promotionSession,
        },
        imageScope,
      ),
    ).toBe(false);
  });

  it("keeps a regular image paywall in the chat flow when no overlay is open", () => {
    expect(
      resolveChatUnlockReturnUrl(
        {
          displayMessageId: "image-1",
          messageId: "image-1",
          kind: "image",
        },
        defaultScope,
      ),
    ).toBe("/chat");
  });
});

function createPendingUnlock(
  input: Pick<
    PendingChatUnlock,
    "displayMessageId" | "messageId" | "kind" | "returnUrl"
  >,
): PendingChatUnlock {
  return {
    reason: "single_message_unlock",
    characterId: "elio",
    ...input,
    stage: "auth",
    createdAt: 1,
  };
}
