/**
 * Unit tests for lib/stripe.ts (Helper Functions)
 * Tests pure calculator functions: subscription cost, setup fees, proration
 */

// Mock Stripe SDK to avoid initialization
jest.mock("stripe", () => {
  return jest.fn().mockImplementation(() => ({
    checkout: { sessions: { create: jest.fn() } },
    customers: { create: jest.fn(), retrieve: jest.fn() },
  }));
});

import {
  calculateSubscriptionCost,
  getSetupFee,
  calculateProration,
} from "@/lib/stripe";

describe("lib/stripe.ts - Helper Functions", () => {
  describe("calculateSubscriptionCost", () => {
    const mockExchangeRates = {
      GBP: 1,
      USD: 1.27,
      EUR: 1.17,
      SAR: 4.76,
      AED: 4.66,
    };

    it("should calculate monthly cost in GBP", () => {
      const cost = calculateSubscriptionCost(
        100,
        "monthly",
        "GBP",
        mockExchangeRates,
      );

      expect(cost).toBe(100); // No discount, no conversion
    });

    it("should apply 7% discount for yearly billing", () => {
      const cost = calculateSubscriptionCost(
        100,
        "yearly",
        "GBP",
        mockExchangeRates,
      );

      expect(cost).toBe(93); // 100 * 0.93 = 93
    });

    it("should convert GBP to USD", () => {
      const cost = calculateSubscriptionCost(
        100,
        "monthly",
        "USD",
        mockExchangeRates,
      );

      expect(cost).toBe(127); // 100 * 1.27 = 127
    });

    it("should convert GBP to SAR", () => {
      const cost = calculateSubscriptionCost(
        100,
        "monthly",
        "SAR",
        mockExchangeRates,
      );

      expect(cost).toBe(476); // 100 * 4.76 = 476
    });

    it("should apply both yearly discount and currency conversion", () => {
      const cost = calculateSubscriptionCost(
        100,
        "yearly",
        "USD",
        mockExchangeRates,
      );

      // 100 * 0.93 (yearly discount) * 1.27 (USD rate) = 118.11
      expect(cost).toBe(118.11);
    });

    it("should apply both yearly discount and SAR conversion", () => {
      const cost = calculateSubscriptionCost(
        100,
        "yearly",
        "SAR",
        mockExchangeRates,
      );

      // 100 * 0.93 (yearly discount) * 4.76 (SAR rate) = 442.68
      expect(cost).toBe(442.68);
    });

    it("should handle decimal base prices", () => {
      const cost = calculateSubscriptionCost(
        99.99,
        "monthly",
        "GBP",
        mockExchangeRates,
      );

      expect(cost).toBe(99.99);
    });

    it("should round to 2 decimal places", () => {
      const cost = calculateSubscriptionCost(
        33.33,
        "yearly",
        "USD",
        mockExchangeRates,
      );

      // 33.33 * 0.93 * 1.27 = 39.35...
      expect(cost.toString()).toMatch(/^\d+\.\d{1,2}$/);
    });

    it("should default to rate 1 for unknown currency", () => {
      const cost = calculateSubscriptionCost(
        100,
        "monthly",
        "XXX",
        mockExchangeRates,
      );

      expect(cost).toBe(100); // Unknown currency defaults to rate 1
    });

    it("should handle zero price", () => {
      const cost = calculateSubscriptionCost(
        0,
        "monthly",
        "GBP",
        mockExchangeRates,
      );

      expect(cost).toBe(0);
    });

    it("should handle very large prices", () => {
      const cost = calculateSubscriptionCost(
        10000,
        "yearly",
        "SAR",
        mockExchangeRates,
      );

      // 10000 * 0.93 * 4.76 = 44268
      expect(cost).toBe(44268);
    });
  });

  describe("getSetupFee", () => {
    it("should return £199 for tier1", () => {
      const fee = getSetupFee("tier1");

      expect(fee).toBe(199);
    });

    it("should return £199 for tier2", () => {
      const fee = getSetupFee("tier2");

      expect(fee).toBe(199);
    });

    it("should return £199 for tier3", () => {
      const fee = getSetupFee("tier3");

      expect(fee).toBe(199);
    });

    it("should return £199 for tier4", () => {
      const fee = getSetupFee("tier4");

      expect(fee).toBe(199);
    });

    it("should return £299 for tier5", () => {
      const fee = getSetupFee("tier5");

      expect(fee).toBe(299);
    });

    it("should default to £199 for unknown tier", () => {
      const fee = getSetupFee("unknown-tier");

      expect(fee).toBe(199);
    });

    it("should default to £199 for empty tier", () => {
      const fee = getSetupFee("");

      expect(fee).toBe(199);
    });

    it("should be consistent across multiple calls", () => {
      const fee1 = getSetupFee("tier2");
      const fee2 = getSetupFee("tier2");

      expect(fee1).toBe(fee2);
    });
  });

  describe("calculateProration", () => {
    it("should calculate upgrade cost (user pays)", () => {
      const proration = calculateProration({
        currentPrice: 100,
        newPrice: 200,
        daysRemaining: 15,
        totalDaysInPeriod: 30,
      });

      // Unused current: (100/30) * 15 = 50
      // New cost: (200/30) * 15 = 100
      // Difference: 100 - 50 = 50 (user pays)
      expect(proration).toBe(50);
    });

    it("should calculate downgrade credit (user receives)", () => {
      const proration = calculateProration({
        currentPrice: 200,
        newPrice: 100,
        daysRemaining: 15,
        totalDaysInPeriod: 30,
      });

      // Unused current: (200/30) * 15 = 100
      // New cost: (100/30) * 15 = 50
      // Difference: 50 - 100 = -50 (user gets credit)
      expect(proration).toBe(-50);
    });

    it("should calculate proration with partial period", () => {
      const proration = calculateProration({
        currentPrice: 150,
        newPrice: 250,
        daysRemaining: 7,
        totalDaysInPeriod: 30,
      });

      // Unused: (150/30) * 7 = 35
      // New: (250/30) * 7 = 58.33...
      // Difference: ~23
      expect(proration).toBe(23);
    });

    it("should return 0 when prices are equal", () => {
      const proration = calculateProration({
        currentPrice: 100,
        newPrice: 100,
        daysRemaining: 15,
        totalDaysInPeriod: 30,
      });

      expect(proration).toBe(0);
    });

    it("should handle start of billing period (full period remaining)", () => {
      const proration = calculateProration({
        currentPrice: 100,
        newPrice: 200,
        daysRemaining: 30,
        totalDaysInPeriod: 30,
      });

      // Full upgrade cost
      expect(proration).toBe(100); // 200 - 100 = 100
    });

    it("should handle end of billing period (minimal days remaining)", () => {
      const proration = calculateProration({
        currentPrice: 100,
        newPrice: 200,
        daysRemaining: 1,
        totalDaysInPeriod: 30,
      });

      // Unused: (100/30) * 1 = 3.33
      // New: (200/30) * 1 = 6.67
      // Difference: ~3
      expect(proration).toBe(3);
    });

    it("should round to nearest integer", () => {
      const proration = calculateProration({
        currentPrice: 99,
        newPrice: 149,
        daysRemaining: 13,
        totalDaysInPeriod: 30,
      });

      // Result should be integer
      expect(Number.isInteger(proration)).toBe(true);
    });

    it("should handle zero price tiers (free tier)", () => {
      const proration = calculateProration({
        currentPrice: 0,
        newPrice: 100,
        daysRemaining: 15,
        totalDaysInPeriod: 30,
      });

      // Full new tier cost for remaining period
      expect(proration).toBe(50); // (100/30) * 15
    });

    it("should handle yearly billing periods (365 days)", () => {
      const proration = calculateProration({
        currentPrice: 1200,
        newPrice: 2400,
        daysRemaining: 180, // Half year remaining
        totalDaysInPeriod: 365,
      });

      // Unused: (1200/365) * 180 = 591.78...
      // New: (2400/365) * 180 = 1183.56...
      // Difference: ~592
      expect(proration).toBeGreaterThan(590);
      expect(proration).toBeLessThan(595);
    });
  });

  describe("Edge Cases", () => {
    it("should handle very small prices", () => {
      const cost = calculateSubscriptionCost(1, "monthly", "GBP", { GBP: 1 });

      expect(cost).toBe(1);
    });

    it("should handle negative proration (downgrade)", () => {
      const proration = calculateProration({
        currentPrice: 500,
        newPrice: 100,
        daysRemaining: 20,
        totalDaysInPeriod: 30,
      });

      expect(proration).toBeLessThan(0); // Negative = credit
    });

    it('should handle same-tier "upgrade" (no change)', () => {
      const proration = calculateProration({
        currentPrice: 150,
        newPrice: 150,
        daysRemaining: 10,
        totalDaysInPeriod: 30,
      });

      expect(proration).toBe(0);
    });
  });

  describe("Business Logic Validation", () => {
    it("should always apply 7% yearly discount regardless of currency", () => {
      const gbpCost = calculateSubscriptionCost(100, "yearly", "GBP", {
        GBP: 1,
      });
      const usdCost = calculateSubscriptionCost(100, "yearly", "USD", {
        USD: 1.27,
      });

      // Both should have 7% discount applied
      expect(gbpCost).toBe(93); // 100 * 0.93
      expect(usdCost).toBe(118.11); // 100 * 0.93 * 1.27
    });

    it("should never apply discount to monthly billing", () => {
      const cost = calculateSubscriptionCost(100, "monthly", "GBP", { GBP: 1 });

      expect(cost).toBe(100); // No discount
    });

    it("should maintain tier5 premium setup fee (£299 vs £199)", () => {
      const tier1Fee = getSetupFee("tier1");
      const tier5Fee = getSetupFee("tier5");

      expect(tier5Fee).toBeGreaterThan(tier1Fee);
      expect(tier5Fee - tier1Fee).toBe(100); // £100 premium
    });
  });
});
