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

import { buildGlobalPageUrl } from "@/router/global-route-context";
import { getCharacterRoutes, ROUTES } from "@/router/routes";

import { consumePendingChatImageReturn } from "../chat_image_return_session";
import {
  clearPendingChatUnlock,
  peekPendingChatUnlock,
} from "../chat_unlock_session";
import {
  consumeSubscriptionExitUrl,
  consumeSubscriptionExplicitExitUrl,
  getSubscriptionFallbackExitUrl,
  peekSubscriptionExplicitExitUrl,
  resolveSubscriptionSuccessExitUrl,
} from "../subscription_exit";

vi.mock("../chat_image_return_session", () => ({
  consumePendingChatImageReturn: vi.fn(),
}));
vi.mock("../chat_unlock_session", () => ({
  clearPendingChatUnlock: vi.fn(),
  peekPendingChatUnlock: vi.fn(),
}));

const consumePendingChatImageReturnMock = vi.mocked(
  consumePendingChatImageReturn,
);
const clearPendingChatUnlockMock = vi.mocked(clearPendingChatUnlock);
const peekPendingChatUnlockMock = vi.mocked(peekPendingChatUnlock);

describe("subscription exit helpers", () => {
  beforeEach(() => {
    consumePendingChatImageReturnMock.mockReset();
    clearPendingChatUnlockMock.mockReset();
    peekPendingChatUnlockMock.mockReset();
  });

  it("uses explicit chat image return urls first", async () => {
    consumePendingChatImageReturnMock.mockResolvedValue({
      reason: "image_paywall",
      characterId: "elio",
      messageId: "msg_1",
      returnUrl: "/chat?image=msg_1",
      createdAt: 1,
    });

    await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
      "/chat?image=msg_1",
    );
  });

  it("falls back to chat when requested", async () => {
    consumePendingChatImageReturnMock.mockResolvedValue(null);
    peekPendingChatUnlockMock.mockResolvedValue(null);

    await expect(consumeSubscriptionExitUrl("chat")).resolves.toBe(
      getCharacterRoutes("elio").chat,
    );
  });

  it("falls back to profile by default", async () => {
    consumePendingChatImageReturnMock.mockResolvedValue(null);
    peekPendingChatUnlockMock.mockResolvedValue(null);

    expect(getSubscriptionFallbackExitUrl(null)).toBe(ROUTES.profile);
    await expect(consumeSubscriptionExitUrl(null)).resolves.toBe(
      ROUTES.profile,
    );
  });

  it("returns to global profile with the source character", async () => {
    const expectedUrl = buildGlobalPageUrl(
      ROUTES.profile,
      getCharacterRoutes("maya").chat,
    );

    expect(getSubscriptionFallbackExitUrl("profile", "maya")).toBe(
      expectedUrl,
    );
    await expect(
      consumeSubscriptionExitUrl("profile", "maya"),
    ).resolves.toBe(expectedUrl);
    await expect(
      resolveSubscriptionSuccessExitUrl("profile", "maya"),
    ).resolves.toBe(expectedUrl);
    expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
    expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
  });

  it("returns directly to private zone without consuming chat state", async () => {
    consumePendingChatImageReturnMock.mockResolvedValue({
      reason: "image_paywall",
      characterId: "elio",
      messageId: "msg_1",
      returnUrl: "/chat?image=msg_1",
      createdAt: 1,
    });
    peekPendingChatUnlockMock.mockResolvedValue({
      reason: "single_message_unlock",
      characterId: "elio",
      displayMessageId: "msg_1",
      messageId: "msg_1",
      kind: "image",
      returnUrl: "/chat?image=msg_1",
      stage: "payment",
      createdAt: 1,
    });

    expect(getSubscriptionFallbackExitUrl("private-zone")).toBe(
      getCharacterRoutes("elio").privateZone,
    );
    await expect(consumeSubscriptionExitUrl("private-zone")).resolves.toBe(
      getCharacterRoutes("elio").privateZone,
    );
    expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
    expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
    expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
  });

  it("keeps private zone ahead of stale chat state after payment", async () => {
    peekPendingChatUnlockMock.mockResolvedValue({
      reason: "single_message_unlock",
      characterId: "elio",
      displayMessageId: "msg_1",
      messageId: "msg_1",
      kind: "image",
      returnUrl: "/chat?image=msg_1",
      stage: "payment",
      createdAt: 1,
    });

    await expect(
      resolveSubscriptionSuccessExitUrl("private-zone", "maya"),
    ).resolves.toBe(getCharacterRoutes("maya").privateZone);
    expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
    expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
  });

  it("keeps pending chat unlocks ahead of chat fallback after payment", async () => {
    peekPendingChatUnlockMock.mockResolvedValue({
      reason: "single_message_unlock",
      characterId: "elio",
      displayMessageId: "msg_1",
      messageId: "msg_1",
      kind: "image",
      returnUrl: "/chat?image=msg_1",
      stage: "payment",
      createdAt: 1,
    });

    await expect(resolveSubscriptionSuccessExitUrl("chat")).resolves.toBe(
      "/chat?image=msg_1",
    );
    expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
  });

  it("peeks chat unlock return urls without clearing them", async () => {
    peekPendingChatUnlockMock.mockResolvedValue({
      reason: "single_message_unlock",
      characterId: "elio",
      displayMessageId: "msg_1",
      messageId: "msg_1",
      kind: "image",
      returnUrl: "/chat?image=msg_1",
      stage: "payment",
      createdAt: 1,
    });

    await expect(peekSubscriptionExplicitExitUrl()).resolves.toBe(
      "/chat?image=msg_1",
    );
    expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
  });

  it("clears chat unlock return urls when consumed", async () => {
    consumePendingChatImageReturnMock.mockResolvedValue(null);
    peekPendingChatUnlockMock.mockResolvedValue({
      reason: "single_message_unlock",
      characterId: "elio",
      displayMessageId: "msg_1",
      messageId: "msg_1",
      kind: "image",
      returnUrl: "/chat?image=msg_1",
      stage: "payment",
      createdAt: 1,
    });

    await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
      "/chat?image=msg_1",
    );
    expect(clearPendingChatUnlockMock).toHaveBeenCalledTimes(1);
  });
});
