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

import {
  GiftProductsResponseSchema,
  PaymentOrderStatusResponseSchema,
  PaymentPlanSchema,
  PaymentPlansResponseSchema,
  TipMessageResponseSchema,
} from "@/data/schemas/payment";

describe("PaymentOrderStatusResponse", () => {
  it("parses the paid gift order shape", () => {
    const response = PaymentOrderStatusResponseSchema.parse({
      orderId: "tip_order_123",
      status: "paid",
      orderType: "tip",
      planId: "tip_coffee_usd_9_99",
      creditsAdded: 0,
    });

    expect(response).toEqual({
      orderId: "tip_order_123",
      status: "paid",
      orderType: "tip",
      planId: "tip_coffee_usd_9_99",
      creditsAdded: 0,
    });
  });

  it("accepts expired status and a nullable plan id", () => {
    expect(
      PaymentOrderStatusResponseSchema.parse({
        orderId: "pay_order_456",
        status: "expired",
        orderType: "tip",
        planId: null,
        creditsAdded: 0,
      }),
    ).toMatchObject({ status: "expired", planId: null, creditsAdded: 0 });
  });
});

describe("PaymentPlan", () => {
  it("parses the camelCase payment plan shape", () => {
    const plan = PaymentPlanSchema.parse({
      planId: "vip_monthly",
      planName: "VIP Monthly",
      orderType: "vip_monthly",
      vipDays: 30,
      dolAmount: null,
      creditBalance: 3000,
      amountCents: 1999,
      originalAmountCents: 2499,
      dailyPriceCents: 66,
      currency: "JPY",
      mostPopular: true,
    });

    expect(plan.planId).toBe("vip_monthly");
    expect(plan.creditBalance).toBe(3000);
    expect(plan.mostPopular).toBe(true);
    expect(plan).toEqual({
      planId: "vip_monthly",
      planName: "VIP Monthly",
      orderType: "vip_monthly",
      vipDays: 30,
      dolAmount: null,
      creditBalance: 3000,
      amountCents: 1999,
      originalAmountCents: 2499,
      dailyPriceCents: 66,
      currency: "JPY",
      isFirstRechargeOffer: false,
      mostPopular: true,
      firstRechargeDiscountPercent: null,
      promotionType: null,
      commercialOfferId: null,
      commercialDiscountPercent: null,
    });
  });

  it("rejects the legacy snake_case payment plan shape", () => {
    expect(() =>
      PaymentPlanSchema.parse({
        plan_id: "vip_monthly",
        plan_name: "VIP Monthly",
        order_type: "vip_monthly",
        amount_cents: 1999,
        original_amount_cents: 2499,
        daily_price_cents: 66,
        currency: "JPY",
        vip_days: 30,
        dol_amount: null,
      }),
    ).toThrow(z.ZodError);
  });

  it("defaults mostPopular to false when the backend omits it", () => {
    const plan = PaymentPlanSchema.parse({
      planId: "vip_monthly",
      planName: "VIP Monthly",
      orderType: "vip_monthly",
      vipDays: 30,
      dolAmount: null,
      creditBalance: 3000,
      amountCents: 1999,
      originalAmountCents: null,
      dailyPriceCents: null,
      currency: "USD",
    });

    expect(plan.mostPopular).toBe(false);
  });
});

describe("PaymentPlansResponse", () => {
  it("parses plans from the new backend response data shape", () => {
    const response = PaymentPlansResponseSchema.parse({
      plans: [
        {
          planId: "dol_1000",
          planName: "1000 Credits",
          orderType: "dol",
          vipDays: null,
          dolAmount: 1000,
          creditBalance: 1000,
          amountCents: 990,
          originalAmountCents: null,
          dailyPriceCents: null,
          currency: "USD",
        },
      ],
    });

    expect(response.plans).toHaveLength(1);
    expect(response.plans[0]?.dolAmount).toBe(1000);
  });

  it("parses first recharge offer metadata", () => {
    const response = PaymentPlansResponseSchema.parse({
      isFirstRecharge: true,
      firstRechargeOffer: {
        enabled: true,
        type: "first_recharge_half_price",
        discountPercent: 50,
      },
      plans: [
        {
          planId: "vip_monthly",
          planName: "VIP Monthly",
          orderType: "vip_monthly",
          vipDays: 30,
          dolAmount: null,
          creditBalance: 3000,
          amountCents: 995,
          originalAmountCents: 1990,
          dailyPriceCents: null,
          currency: "USD",
          isFirstRechargeOffer: true,
          firstRechargeDiscountPercent: 50,
          promotionType: "first_recharge_half_price",
        },
      ],
    });

    expect(response.isFirstRecharge).toBe(true);
    expect(response.firstRechargeOffer?.discountPercent).toBe(50);
    expect(response.plans[0]).toMatchObject({
      amountCents: 995,
      originalAmountCents: 1990,
      isFirstRechargeOffer: true,
      firstRechargeDiscountPercent: 50,
      promotionType: "first_recharge_half_price",
    });
  });

  it("defaults nullable first recharge offer metadata", () => {
    const response = PaymentPlansResponseSchema.parse({
      isFirstRecharge: true,
      firstRechargeOffer: {
        enabled: null,
        type: null,
        discountPercent: null,
      },
      plans: [],
    });

    expect(response.firstRechargeOffer).toEqual({
      enabled: false,
      type: "",
      discountPercent: 0,
    });
  });

  it("parses one user-bound commercial offer and its discounted plan", () => {
    const response = PaymentPlansResponseSchema.parse({
        supportCharacterId: "maya-tan",
        commercialOffer: {
          enabled: true,
          commercialOfferId: "offer-1",
          characterId: "maya-tan",
        planId: "vip_annual",
        discountPercent: 30,
        pricePercent: 70,
        expiresAt: "2026-07-24T08:00:00+00:00",
        triggerReason: "price_objection",
        message: "I got this private price for you.",
      },
      plans: [
        {
          planId: "vip_annual",
          planName: "Annual VIP",
          orderType: "vip_annual",
          vipDays: 365,
          dolAmount: null,
          creditBalance: 9000,
          amountCents: 12593,
          originalAmountCents: 17990,
          dailyPriceCents: 34,
          currency: "USD",
          promotionType: "commercial_seven_discount",
          commercialOfferId: "offer-1",
          commercialDiscountPercent: 30,
        },
      ],
    });

    expect(response.commercialOffer?.commercialOfferId).toBe("offer-1");
    expect(response.supportCharacterId).toBe("maya-tan");
    expect(response.commercialOffer?.characterId).toBe("maya-tan");
    expect(response.plans[0]).toMatchObject({
      planId: "vip_annual",
      commercialOfferId: "offer-1",
      commercialDiscountPercent: 30,
    });
  });
});

describe("GiftProductsResponse", () => {
  it("parses and freezes categories and complete gift products", () => {
    const response = GiftProductsResponseSchema.parse({
      characterId: "elio",
      categories: [
        {
          category: "coffee",
          name: "Coffee",
          productCount: 1,
          imageUrl: null,
        },
      ],
      plans: [
        {
          planId: "tip_coffee_usd_4_99",
          planName: "Velvet Espresso",
          orderType: "tip",
          tipType: "coffee_small",
          category: "coffee",
          characterId: "elio",
          description: "Buy Elio a small coffee",
          imageUrl: null,
          amountCents: 499,
          currency: "USD",
          autoRenew: false,
          isFirstRechargeOffer: false,
          firstRechargeDiscountPercent: 0,
          promotionType: null,
        },
      ],
    });

    expect(response.categories[0]?.category).toBe("coffee");
    expect(response.plans[0]?.description).toBe("Buy Elio a small coffee");
    expect(Object.isFrozen(response)).toBe(true);
    expect(Object.isFrozen(response.categories)).toBe(true);
    expect(Object.isFrozen(response.plans[0])).toBe(true);
  });
});

describe("TipMessageResponse", () => {
  it("parses the complete stable backend message", () => {
    const response = TipMessageResponseSchema.parse({
      orderId: "pay_xxx",
      characterId: "elio",
      planId: "tip_coffee_usd_4_99",
      productName: "Velvet Espresso",
      tipCount: 2,
      poolIndex: 37,
      message: "You have a knack for making me smile.",
    });

    expect(response.message).toBe("You have a knack for making me smile.");
  });
});
