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

import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
import {
  ChatMessageSchema,
  ChatSendResponseSchema,
  type ChatMessage,
  type ChatMessageInput,
  type ChatSendResponse,
  type ChatSendResponseInput,
} from "@/data/schemas/chat";

import {
  buildChatMediaCacheKey,
  fallbackChatMediaMimeType,
  getMessageMediaTargets,
  getSendResponseMediaTargets,
  uniqueMediaTargets,
} from "../chat_media_cache_helpers";

function makeMessage(overrides: Partial<ChatMessageInput> = {}): ChatMessage {
  return ChatMessageSchema.parse({
    id: "msg-1",
    role: "assistant",
    type: "image",
    content: "",
    createdAt: "2026-06-30T00:00:00.000Z",
    audioUrl: null,
    image: { type: null, url: null },
    lockDetail: {
      locked: false,
      reason: null,
    },
    ...overrides,
  });
}

function makeResponse(
  overrides: Partial<ChatSendResponseInput> = {},
): ChatSendResponse {
  return ChatSendResponseSchema.parse({
    reply: "",
    messageId: "msg-1",
    isGuest: false,
    timestamp: 1782356425363,
    image: { type: null, url: null },
    lockDetail: {
      locked: false,
      reason: null,
    },
    ...overrides,
  });
}

describe("chat media cache helpers", () => {
  it("builds owner-scoped media cache keys", () => {
    expect(
      buildChatMediaCacheKey({
        ownerKey: "user:u1",
        messageId: "msg-1",
        kind: "image",
      }),
    ).toBe("user:u1:msg-1:image");
  });

  it("extracts cacheable media targets from history messages", () => {
    expect(
      getMessageMediaTargets(
        makeMessage({
          audioUrl: "https://example.com/a.mp3",
          image: { type: "jpg", url: "https://example.com/a.jpg" },
        }),
        DEFAULT_CHARACTER_ID,
      ),
    ).toEqual([
      {
        characterId: DEFAULT_CHARACTER_ID,
        messageId: "msg-1",
        kind: "image",
        remoteUrl: "https://example.com/a.jpg",
      },
      {
        characterId: DEFAULT_CHARACTER_ID,
        messageId: "msg-1",
        kind: "audio",
        remoteUrl: "https://example.com/a.mp3",
      },
    ]);
  });

  it("ignores empty message ids and non-remote media urls", () => {
    expect(
      getSendResponseMediaTargets(
        makeResponse({
          messageId: "",
          audioUrl: "https://example.com/a.mp3",
          image: { type: "png", url: "data:image/png;base64,abc" },
        }),
        DEFAULT_CHARACTER_ID,
      ),
    ).toEqual([]);
  });

  it("does not cache audio from a locked send response", () => {
    expect(
      getSendResponseMediaTargets(
        makeResponse({
          audioUrl: "https://example.com/locked.mp3",
          lockDetail: { locked: true, reason: "voice_message" },
        }),
        DEFAULT_CHARACTER_ID,
      ),
    ).toEqual([]);
  });

  it("caches audio from an unlocked send response", () => {
    expect(
      getSendResponseMediaTargets(
        makeResponse({
          audioUrl: "https://example.com/unlocked.mp3",
        }),
        DEFAULT_CHARACTER_ID,
      ),
    ).toEqual([
      {
        characterId: DEFAULT_CHARACTER_ID,
        messageId: "msg-1",
        kind: "audio",
        remoteUrl: "https://example.com/unlocked.mp3",
      },
    ]);
  });

  it("deduplicates media targets", () => {
    expect(
      uniqueMediaTargets([
        {
          characterId: DEFAULT_CHARACTER_ID,
          messageId: "msg-1",
          kind: "image",
          remoteUrl: "https://x/a.jpg",
        },
        {
          characterId: DEFAULT_CHARACTER_ID,
          messageId: "msg-1",
          kind: "image",
          remoteUrl: "https://x/a.jpg",
        },
        {
          characterId: DEFAULT_CHARACTER_ID,
          messageId: "msg-1",
          kind: "audio",
          remoteUrl: "https://x/a.jpg",
        },
      ]),
    ).toEqual([
      {
        characterId: DEFAULT_CHARACTER_ID,
        messageId: "msg-1",
        kind: "image",
        remoteUrl: "https://x/a.jpg",
      },
      {
        characterId: DEFAULT_CHARACTER_ID,
        messageId: "msg-1",
        kind: "audio",
        remoteUrl: "https://x/a.jpg",
      },
    ]);
  });

  it("provides fallback mime types", () => {
    expect(fallbackChatMediaMimeType("image")).toBe("image/*");
    expect(fallbackChatMediaMimeType("audio")).toBe("audio/mpeg");
  });
});
