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

import { UnlockPrivateResponse } from "@/data/dto/chat";

describe("UnlockPrivateResponse", () => {
  it("parses a successful single-message unlock response", () => {
    const response = UnlockPrivateResponse.from({
      unlocked: true,
      content: "完整消息内容",
      audioUrl: "https://example.com/unlocked-voice.mp3",
      reason: "ok",
      creditBalance: 9180,
      creditsCharged: 10,
      requiredCredits: 10,
      shortfallCredits: 0,
    });

    expect(response.unlocked).toBe(true);
    expect(response.content).toBe("完整消息内容");
    expect(response.audioUrl).toBe("https://example.com/unlocked-voice.mp3");
    expect(response.reason).toBe("ok");
    expect(response.creditBalance).toBe(9180);
    expect(response.creditsCharged).toBe(10);
    expect(response.requiredCredits).toBe(10);
    expect(response.shortfallCredits).toBe(0);
  });

  it("normalizes backend ids, audio aliases, and unlocked images", () => {
    const response = UnlockPrivateResponse.from({
      unlocked: true,
      message_id: "backend-message-1",
      clientLockId: "promotion-1",
      lockType: "image_paywall",
      content: null,
      reply: "Unlocked reply",
      audio_url: "https://example.com/audio.mp3",
      image: {
        type: "promotion",
        url: "https://example.com/image.jpg",
      },
    });

    expect(response.messageId).toBe("backend-message-1");
    expect(response.clientLockId).toBe("promotion-1");
    expect(response.lockType).toBe("image_paywall");
    expect(response.content).toBe("Unlocked reply");
    expect(response.audioUrl).toBe("https://example.com/audio.mp3");
    expect(response.image.url).toBe("https://example.com/image.jpg");
  });

  it("parses an insufficient-balance unlock response", () => {
    const response = UnlockPrivateResponse.from({
      unlocked: false,
      content: "",
      reason: "insufficient_balance",
      creditBalance: 5,
      creditsCharged: 0,
      requiredCredits: 10,
      shortfallCredits: 5,
    });

    expect(response.unlocked).toBe(false);
    expect(response.reason).toBe("insufficient_balance");
    expect(response.creditBalance).toBe(5);
    expect(response.creditsCharged).toBe(0);
    expect(response.requiredCredits).toBe(10);
    expect(response.shortfallCredits).toBe(5);
  });

  it("defaults nullable content to an empty string", () => {
    const response = UnlockPrivateResponse.from({
      unlocked: false,
      content: null,
      audioUrl: null,
      reason: "insufficient_balance",
    });

    expect(response.content).toBe("");
    expect(response.audioUrl).toBe("");
  });

  it("defaults nullable credit fields to zero", () => {
    const response = UnlockPrivateResponse.from({
      unlocked: false,
      content: "",
      reason: "insufficient_balance",
      creditBalance: null,
      creditsCharged: null,
      requiredCredits: null,
      shortfallCredits: null,
    });

    expect(response.creditBalance).toBe(0);
    expect(response.creditsCharged).toBe(0);
    expect(response.requiredCredits).toBe(0);
    expect(response.shortfallCredits).toBe(0);
  });

  it("strips legacy lock detail fields", () => {
    const response = UnlockPrivateResponse.fromJson({
      unlocked: false,
      lockDetail: {
        locked: true,
        reason: "private_message",
        showContent: false,
        showUpgrade: true,
        hint: "Legacy hint",
        detail: { messageId: "legacy-message" },
      },
    });

    expect(response.toJson()).not.toHaveProperty("lockDetail");
    expect(response).not.toHaveProperty("lockDetail");
  });
});
