/**
 * Yearly Pricing Validation Tests
 *
 * These tests ensure that yearly subscription pricing is calculated correctly:
 * - GBP to QAR conversion (rate: 4.62)
 * - 7% yearly discount applied correctly
 * - All tier prices match expected values
 * - Stripe configuration is valid
 *
 * CRITICAL: If these tests fail, yearly subscriptions may charge incorrect amounts!
 */

import { PRICING_TIERS } from "@/lib/config/pricing-tiers";
import { PRICING_CONFIG } from "@/lib/config/pricing-constants";
import {
  YEARLY_DISCOUNT_PERCENT,
  YEARLY_DISCOUNT_MULTIPLIER,
  calculateYearlyTotal,
  calculateYearlyTotalCents,
  calculateMonthlyEquivalent,
} from "@/lib/utils/pricing-helpers";

// Exchange rate constants (must match CurrencyManager)
const GBP_TO_QAR_RATE = 4.62;

// Expected tier prices (source of truth from pricing-tiers.ts)
const EXPECTED_TIER_PRICES_GBP = {
  tier1: 179,
  tier2: 209,
  tier3: 249,
  tier4: 349,
  tier5: 449,
};

// Helper to convert GBP to QAR
const gbpToQar = (gbp: number): number => Math.round(gbp * GBP_TO_QAR_RATE);
const gbpToQarCents = (gbp: number): number =>
  Math.round(gbp * GBP_TO_QAR_RATE * 100);

describe("Yearly Pricing Validation", () => {
  describe("Discount Configuration", () => {
    it("should have 7% yearly discount configured", () => {
      expect(YEARLY_DISCOUNT_PERCENT).toBe(7);
      expect(PRICING_CONFIG.YEARLY_DISCOUNT_PERCENT).toBe(7);
    });

    it("should have correct discount multiplier (0.93)", () => {
      expect(YEARLY_DISCOUNT_MULTIPLIER).toBeCloseTo(0.93, 2);
    });

    it("should match discount between constants and helpers", () => {
      const configDiscount = 1 - PRICING_CONFIG.YEARLY_DISCOUNT_PERCENT / 100;
      expect(YEARLY_DISCOUNT_MULTIPLIER).toBeCloseTo(configDiscount, 2);
    });
  });

  describe("GBP to QAR Conversion", () => {
    it("should convert tier1 correctly: £179 → 827 QAR", () => {
      expect(gbpToQar(179)).toBe(827);
    });

    it("should convert tier2 correctly: £209 → 966 QAR", () => {
      expect(gbpToQar(209)).toBe(966);
    });

    it("should convert tier3 correctly: £249 → 1150 QAR", () => {
      expect(gbpToQar(249)).toBe(1150);
    });

    it("should convert tier4 correctly: £349 → 1612 QAR", () => {
      expect(gbpToQar(349)).toBe(1612);
    });

    it("should convert tier5 correctly: £449 → 2074 QAR", () => {
      expect(gbpToQar(449)).toBe(2074);
    });
  });

  describe("Yearly Total Calculation (QAR)", () => {
    /**
     * Formula: Monthly QAR × 12 × 0.93
     * These are the amounts Stripe should charge annually
     */

    it("should calculate tier1 yearly: 827 × 12 × 0.93 ≈ 9,229 QAR", () => {
      const monthlyQar = gbpToQar(179);
      const yearlyTotal = calculateYearlyTotal(monthlyQar);

      expect(yearlyTotal).toBeGreaterThan(9200);
      expect(yearlyTotal).toBeLessThan(9300);

      // Verify it's exactly monthly × 12 × 0.93
      const expected = monthlyQar * 12 * 0.93;
      expect(yearlyTotal).toBeCloseTo(expected, 0);
    });

    it("should calculate tier2 yearly: 966 × 12 × 0.93 ≈ 10,776 QAR", () => {
      const monthlyQar = gbpToQar(209);
      const yearlyTotal = calculateYearlyTotal(monthlyQar);

      expect(yearlyTotal).toBeGreaterThan(10700);
      expect(yearlyTotal).toBeLessThan(10850);
    });

    it("should calculate tier3 yearly: 1150 × 12 × 0.93 ≈ 12,834 QAR", () => {
      const monthlyQar = gbpToQar(249);
      const yearlyTotal = calculateYearlyTotal(monthlyQar);

      expect(yearlyTotal).toBeGreaterThan(12800);
      expect(yearlyTotal).toBeLessThan(12900);
    });

    it("should calculate tier4 yearly: 1612 × 12 × 0.93 ≈ 17,990 QAR", () => {
      const monthlyQar = gbpToQar(349);
      const yearlyTotal = calculateYearlyTotal(monthlyQar);

      expect(yearlyTotal).toBeGreaterThan(17900);
      expect(yearlyTotal).toBeLessThan(18100);
    });

    it("should calculate tier5 yearly: 2074 × 12 × 0.93 ≈ 23,145 QAR", () => {
      const monthlyQar = gbpToQar(449);
      const yearlyTotal = calculateYearlyTotal(monthlyQar);

      expect(yearlyTotal).toBeGreaterThan(23100);
      expect(yearlyTotal).toBeLessThan(23200);
    });
  });

  describe("Yearly Total in Cents (for Stripe)", () => {
    /**
     * Stripe requires amounts in cents (smallest currency unit)
     * These values should match what's configured in Stripe
     */

    it("should calculate tier1 yearly in cents correctly", () => {
      const monthlyQarCents = gbpToQarCents(179);
      const yearlyTotalCents = calculateYearlyTotalCents(monthlyQarCents);

      // Should be around 922,900 cents (9,229 QAR)
      expect(yearlyTotalCents).toBeGreaterThan(920000);
      expect(yearlyTotalCents).toBeLessThan(930000);
    });

    it("should calculate tier5 yearly in cents correctly", () => {
      const monthlyQarCents = gbpToQarCents(449);
      const yearlyTotalCents = calculateYearlyTotalCents(monthlyQarCents);

      // Should be around 2,315,000 cents (23,150 QAR)
      expect(yearlyTotalCents).toBeGreaterThan(2310000);
      expect(yearlyTotalCents).toBeLessThan(2320000);
    });
  });

  describe("Monthly Equivalent (Discounted)", () => {
    /**
     * Monthly equivalent = Monthly price × 0.93
     * This is displayed on pricing pages as "per month, billed yearly"
     */

    it("should calculate tier1 monthly equivalent: 827 × 0.93 ≈ 769 QAR", () => {
      const monthlyQar = gbpToQar(179);
      const monthlyEquiv = calculateMonthlyEquivalent(monthlyQar);

      expect(monthlyEquiv).toBeCloseTo(769, 0);
    });

    it("should calculate tier5 monthly equivalent: 2074 × 0.93 ≈ 1929 QAR", () => {
      const monthlyQar = gbpToQar(449);
      const monthlyEquiv = calculateMonthlyEquivalent(monthlyQar);

      expect(monthlyEquiv).toBeCloseTo(1929, 0);
    });
  });

  describe("Savings Calculation", () => {
    it("should save exactly 7% on yearly billing", () => {
      const monthlyQar = gbpToQar(349); // tier4
      const regularYearlyTotal = monthlyQar * 12;
      const discountedYearlyTotal = calculateYearlyTotal(monthlyQar);

      const savings = regularYearlyTotal - discountedYearlyTotal;
      const savingsPercent = (savings / regularYearlyTotal) * 100;

      expect(savingsPercent).toBeCloseTo(7, 1);
    });

    it("should calculate correct savings amounts", () => {
      // tier5: 2074 QAR/month
      const monthlyQar = gbpToQar(449);
      const regularYearly = monthlyQar * 12; // 24,888 QAR
      const discountedYearly = calculateYearlyTotal(monthlyQar); // ~23,146 QAR
      const savings = regularYearly - discountedYearly;

      // 7% of 24,888 ≈ 1,742 QAR saved
      expect(savings).toBeGreaterThan(1700);
      expect(savings).toBeLessThan(1800);
    });
  });

  describe("Pricing Tiers Configuration", () => {
    it("should have 5 pricing tiers defined", () => {
      expect(PRICING_TIERS).toHaveLength(5);
    });

    it("should have correct GBP prices for all tiers", () => {
      const tierPrices = PRICING_TIERS.reduce(
        (acc, tier) => {
          acc[tier.id] = tier.priceGBP;
          return acc;
        },
        {} as Record<string, number>,
      );

      expect(tierPrices.tier1).toBe(EXPECTED_TIER_PRICES_GBP.tier1);
      expect(tierPrices.tier2).toBe(EXPECTED_TIER_PRICES_GBP.tier2);
      expect(tierPrices.tier3).toBe(EXPECTED_TIER_PRICES_GBP.tier3);
      expect(tierPrices.tier4).toBe(EXPECTED_TIER_PRICES_GBP.tier4);
      expect(tierPrices.tier5).toBe(EXPECTED_TIER_PRICES_GBP.tier5);
    });

    it("should have tier prices in ascending order", () => {
      const prices = PRICING_TIERS.map((t) => t.priceGBP);

      for (let i = 1; i < prices.length; i++) {
        expect(prices[i]).toBeGreaterThan(prices[i - 1]);
      }
    });
  });

  describe("All Tiers Yearly Pricing (Comprehensive)", () => {
    /**
     * Comprehensive test that validates all tiers at once
     * This is the main regression test for yearly pricing
     */

    const expectedYearlyPricesQAR = {
      tier1: { min: 9200, max: 9300 }, // ~9,229 QAR
      tier2: { min: 10700, max: 10850 }, // ~10,776 QAR
      tier3: { min: 12800, max: 12900 }, // ~12,838 QAR
      tier4: { min: 17900, max: 18100 }, // ~17,994 QAR
      tier5: { min: 23100, max: 23200 }, // ~23,150 QAR
    };

    Object.entries(EXPECTED_TIER_PRICES_GBP).forEach(([tierId, priceGBP]) => {
      it(`should calculate correct yearly price for ${tierId} (£${priceGBP}/month)`, () => {
        const monthlyQar = gbpToQar(priceGBP);
        const yearlyTotal = calculateYearlyTotal(monthlyQar);
        const expected =
          expectedYearlyPricesQAR[
            tierId as keyof typeof expectedYearlyPricesQAR
          ];

        expect(yearlyTotal).toBeGreaterThan(expected.min);
        expect(yearlyTotal).toBeLessThan(expected.max);

        // Also verify the formula is applied correctly
        const calculatedYearly = monthlyQar * 12 * YEARLY_DISCOUNT_MULTIPLIER;
        expect(yearlyTotal).toBeCloseTo(calculatedYearly, 0);
      });
    });
  });

  describe("Edge Cases", () => {
    it("should handle zero price gracefully", () => {
      const result = calculateYearlyTotal(0);
      expect(result).toBe(0);
    });

    it("should handle very small prices", () => {
      const result = calculateYearlyTotal(1);
      // 1 × 12 × 0.93 = 11.16
      expect(result).toBeCloseTo(11.16, 1);
    });

    it("should handle large prices correctly", () => {
      const largeMonthlyQar = 10000;
      const result = calculateYearlyTotal(largeMonthlyQar);
      // 10000 × 12 × 0.93 = 111,600
      expect(result).toBeCloseTo(111600, 0);
    });

    it("should round cents correctly (no floating point errors)", () => {
      const monthlyQarCents = 82698; // tier1 in cents
      const yearlyTotalCents = calculateYearlyTotalCents(monthlyQarCents);

      // Should be an integer (no decimal points in cents)
      expect(Number.isInteger(yearlyTotalCents)).toBe(true);
    });
  });

  describe("Formula Consistency", () => {
    it("should have yearly total equal to 12 × monthly equivalent", () => {
      Object.values(EXPECTED_TIER_PRICES_GBP).forEach((priceGBP) => {
        const monthlyQar = gbpToQar(priceGBP);
        const yearlyTotal = calculateYearlyTotal(monthlyQar);
        const monthlyEquiv = calculateMonthlyEquivalent(monthlyQar);

        // Yearly should equal 12 × monthly equivalent
        expect(yearlyTotal).toBeCloseTo(monthlyEquiv * 12, 1);
      });
    });

    it("should maintain consistent savings percentage across all tiers", () => {
      Object.values(EXPECTED_TIER_PRICES_GBP).forEach((priceGBP) => {
        const monthlyQar = gbpToQar(priceGBP);
        const regularYearly = monthlyQar * 12;
        const discountedYearly = calculateYearlyTotal(monthlyQar);
        const savingsPercent =
          ((regularYearly - discountedYearly) / regularYearly) * 100;

        // All tiers should have 7% savings
        expect(savingsPercent).toBeCloseTo(7, 1);
      });
    });
  });
});

describe("Stripe Configuration Validation", () => {
  let stripePricesConfig: any;

  beforeAll(() => {
    // Load Stripe prices config
    stripePricesConfig = require("@/lib/config/stripe-prices.json");
  });

  it("should have stripe-prices.json file", () => {
    expect(stripePricesConfig).toBeDefined();
  });

  it("should have all 5 tiers configured", () => {
    expect(stripePricesConfig.tiers).toBeDefined();
    expect(Object.keys(stripePricesConfig.tiers)).toHaveLength(5);
  });

  it("should have productId for all tiers", () => {
    Object.entries(stripePricesConfig.tiers).forEach(
      ([tierId, config]: [string, any]) => {
        expect(config.productId).toBeDefined();
        expect(config.productId).toMatch(/^prod_/);
      },
    );
  });

  it("should have monthly price ID for all tiers", () => {
    Object.entries(stripePricesConfig.tiers).forEach(
      ([tierId, config]: [string, any]) => {
        expect(config.monthly).toBeDefined();
        expect(config.monthly).toMatch(/^price_/);
      },
    );
  });

  it("should have yearly price ID for all tiers", () => {
    Object.entries(stripePricesConfig.tiers).forEach(
      ([tierId, config]: [string, any]) => {
        expect(config.yearly).toBeDefined();
        expect(config.yearly).toMatch(/^price_/);
      },
    );
  });

  it("should have yearly discount percent configured", () => {
    expect(stripePricesConfig.yearlyDiscountPercent).toBe(7);
  });

  it("should have lastUpdated timestamp", () => {
    expect(stripePricesConfig.lastUpdated).toBeDefined();
    // Verify it's a valid ISO date string
    const date = new Date(stripePricesConfig.lastUpdated);
    expect(date.getTime()).not.toBeNaN();
  });
});
