/**
 * Unit tests for quotation Stripe currency fallback logic.
 *
 * The getStripeCurrency() function and STRIPE_CURRENCIES / STRIPE_SUPPORTED_CURRENCIES
 * sets are defined inline in three route handlers:
 *   - app/api/quotations/portal/[token]/pay/route.ts  (STRIPE_SUPPORTED_CURRENCIES — large set)
 *   - app/api/dashboard/quotations/route.ts            (STRIPE_CURRENCIES — smaller set)
 *   - app/api/dashboard/quotations/[id]/send/route.ts  (STRIPE_CURRENCIES — smaller set)
 *
 * Since these are not exported, we duplicate the logic here for pure-function testing.
 */

// ── Portal pay route: large Stripe-supported set ──────────────────────────────
const STRIPE_SUPPORTED_CURRENCIES = new Set([
  "usd","aed","afn","all","amd","ang","aoa","ars","aud","awg","azn","bam","bbd",
  "bdt","bgn","bif","bmd","bnd","bob","brl","bsd","bwp","byn","bzd","cad","cdf",
  "chf","clp","cny","cop","crc","cve","czk","djf","dkk","dop","dzd","egp","etb",
  "eur","fjd","fkp","gbp","gel","gip","gmd","gnf","gtq","gyd","hkd","hnl","hrk",
  "htg","huf","idr","ils","inr","isk","jmd","jpy","kes","kgs","khr","kmf","krw",
  "kyd","kzt","lak","lbp","lkr","lrd","lsl","mad","mdl","mga","mkd","mmk","mnt",
  "mop","mur","mvr","mwk","mxn","myr","mzn","nad","ngn","nio","nok","npr","nzd",
  "pab","pen","pgk","php","pkr","pln","pyg","qar","ron","rsd","rub","rwf","sar",
  "sbd","scr","sek","sgd","shp","sle","sos","srd","std","szl","thb","tjs","top",
  "try","ttd","twd","tzs","uah","ugx","uyu","uzs","vnd","vuv","wst","xaf","xcd",
  "xcg","xof","xpf","yer","zar","zmw",
]);

function getStripeCurrencyPortal(currency: string): string {
  const lower = currency.toLowerCase();
  return STRIPE_SUPPORTED_CURRENCIES.has(lower) ? lower : "usd";
}

// ── Dashboard routes: smaller curated set ─────────────────────────────────────
const STRIPE_CURRENCIES = new Set([
  "usd","aed","aud","brl","cad","chf","cny","czk","dkk","eur","gbp","hkd",
  "huf","idr","ils","inr","jpy","krw","mxn","myr","nok","nzd","php","pkr",
  "pln","qar","ron","sar","sek","sgd","thb","try","twd","uah","zar",
]);

function getStripeCurrencyDashboard(c: string): string {
  const l = c.toLowerCase();
  return STRIPE_CURRENCIES.has(l) ? l : "usd";
}

// ── Currency note helper (extracted from route logic) ─────────────────────────
function buildCurrencyNote(
  originalCurrency: string,
  stripeCurrency: string,
  total: number,
): string {
  return stripeCurrency !== originalCurrency.toLowerCase()
    ? ` (${originalCurrency.toUpperCase()} ${total.toFixed(2)})`
    : "";
}

// =============================================================================
// Tests
// =============================================================================

describe("Quotation Stripe Currency Fallback", () => {
  // ── Portal route (large set) ────────────────────────────────────────────────
  describe("getStripeCurrency — portal route (STRIPE_SUPPORTED_CURRENCIES)", () => {
    describe("supported GCC currencies pass through", () => {
      it.each([
        ["qar", "qar"],
        ["sar", "sar"],
        ["aed", "aed"],
        ["usd", "usd"],
        ["eur", "eur"],
        ["gbp", "gbp"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyPortal(input)).toBe(expected);
      });
    });

    describe("unsupported currencies fall back to usd", () => {
      it.each([
        ["omr", "usd"],
        ["bhd", "usd"],
        ["kwd", "usd"],
        ["iqd", "usd"],
        ["xyz", "usd"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyPortal(input)).toBe(expected);
      });
    });

    describe("case insensitive", () => {
      it.each([
        ["QAR", "qar"],
        ["USD", "usd"],
        ["Eur", "eur"],
        ["GBP", "gbp"],
        ["SAR", "sar"],
        ["AED", "aed"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyPortal(input)).toBe(expected);
      });
    });

    describe("edge cases", () => {
      it("empty string falls back to usd", () => {
        expect(getStripeCurrencyPortal("")).toBe("usd");
      });

      it("whitespace-only string falls back to usd", () => {
        expect(getStripeCurrencyPortal("  ")).toBe("usd");
      });

      it("numeric string falls back to usd", () => {
        expect(getStripeCurrencyPortal("123")).toBe("usd");
      });
    });

    describe("comprehensive Stripe-supported currencies", () => {
      it.each([
        "usd", "eur", "gbp", "jpy", "aud", "cad", "chf", "cny", "inr",
        "mxn", "brl", "krw", "sgd", "hkd", "nzd", "sek", "nok", "dkk",
        "pln", "czk", "huf", "ron", "thb", "myr", "php", "idr", "zar",
        "try", "twd", "uah", "pkr", "ils", "qar", "sar", "aed",
      ])("passes through supported currency: %s", (currency) => {
        expect(getStripeCurrencyPortal(currency)).toBe(currency);
      });
    });
  });

  // ── Dashboard routes (smaller set) ─────────────────────────────────────────
  describe("getStripeCurrency — dashboard routes (STRIPE_CURRENCIES)", () => {
    describe("supported currencies pass through", () => {
      it.each([
        ["qar", "qar"],
        ["sar", "sar"],
        ["aed", "aed"],
        ["usd", "usd"],
        ["eur", "eur"],
        ["gbp", "gbp"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyDashboard(input)).toBe(expected);
      });
    });

    describe("unsupported currencies fall back to usd", () => {
      it.each([
        ["omr", "usd"],
        ["bhd", "usd"],
        ["kwd", "usd"],
        ["iqd", "usd"],
        ["xyz", "usd"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyDashboard(input)).toBe(expected);
      });
    });

    describe("case insensitive", () => {
      it.each([
        ["QAR", "qar"],
        ["USD", "usd"],
        ["Eur", "eur"],
        ["GBP", "gbp"],
      ])("%s -> %s", (input, expected) => {
        expect(getStripeCurrencyDashboard(input)).toBe(expected);
      });
    });

    describe("currencies in portal set but NOT in dashboard set", () => {
      // The dashboard set is smaller — some currencies valid for portal
      // will fall back to usd in the dashboard context
      it.each([
        "afn", "all", "amd", "ang", "aoa", "ars", "awg", "azn", "bam",
        "bbd", "bdt", "bgn", "bif", "bmd", "bnd", "bob", "bsd", "bwp",
      ])("dashboard falls back for: %s", (currency) => {
        // These are in the portal set but not the dashboard set
        if (!STRIPE_CURRENCIES.has(currency)) {
          expect(getStripeCurrencyDashboard(currency)).toBe("usd");
        }
      });
    });

    describe("edge cases", () => {
      it("empty string falls back to usd", () => {
        expect(getStripeCurrencyDashboard("")).toBe("usd");
      });

      it("whitespace-only string falls back to usd", () => {
        expect(getStripeCurrencyDashboard("  ")).toBe("usd");
      });
    });
  });

  // ── Set consistency ─────────────────────────────────────────────────────────
  describe("set consistency", () => {
    it("dashboard set is a subset of portal set", () => {
      for (const currency of STRIPE_CURRENCIES) {
        expect(STRIPE_SUPPORTED_CURRENCIES.has(currency)).toBe(true);
      }
    });

    it("portal set is larger than dashboard set", () => {
      expect(STRIPE_SUPPORTED_CURRENCIES.size).toBeGreaterThan(
        STRIPE_CURRENCIES.size,
      );
    });

    it("both sets contain all GCC currencies supported by Stripe", () => {
      // QAR, SAR, AED are Stripe-supported GCC currencies
      for (const gcc of ["qar", "sar", "aed"]) {
        expect(STRIPE_SUPPORTED_CURRENCIES.has(gcc)).toBe(true);
        expect(STRIPE_CURRENCIES.has(gcc)).toBe(true);
      }
    });

    it("neither set contains OMR, BHD, or KWD (unsupported by Stripe)", () => {
      for (const unsupported of ["omr", "bhd", "kwd"]) {
        expect(STRIPE_SUPPORTED_CURRENCIES.has(unsupported)).toBe(false);
        expect(STRIPE_CURRENCIES.has(unsupported)).toBe(false);
      }
    });
  });

  // ── Currency note generation ───────────────────────────────────────────────
  describe("currency note generation", () => {
    it("returns empty string when currencies match", () => {
      expect(buildCurrencyNote("qar", "qar", 1509.56)).toBe("");
      expect(buildCurrencyNote("usd", "usd", 100.0)).toBe("");
      expect(buildCurrencyNote("eur", "eur", 250.0)).toBe("");
    });

    it("returns note with original currency when fallback occurs", () => {
      expect(buildCurrencyNote("OMR", "usd", 1509.56)).toBe(
        " (OMR 1509.56)",
      );
      expect(buildCurrencyNote("BHD", "usd", 500.0)).toBe(
        " (BHD 500.00)",
      );
      expect(buildCurrencyNote("KWD", "usd", 75.5)).toBe(
        " (KWD 75.50)",
      );
    });

    it("handles case where original is uppercase and stripe is lowercase", () => {
      // QAR -> qar: same currency, no note
      expect(buildCurrencyNote("QAR", "qar", 100)).toBe("");
    });

    it("handles zero total", () => {
      expect(buildCurrencyNote("OMR", "usd", 0)).toBe(" (OMR 0.00)");
    });

    it("handles large totals with proper decimal formatting", () => {
      expect(buildCurrencyNote("BHD", "usd", 999999.999)).toBe(
        " (BHD 1000000.00)",
      );
    });

    it("formats to exactly 2 decimal places", () => {
      expect(buildCurrencyNote("KWD", "usd", 100.1)).toBe(
        " (KWD 100.10)",
      );
      expect(buildCurrencyNote("KWD", "usd", 100)).toBe(
        " (KWD 100.00)",
      );
    });
  });

  // ── Product name construction ──────────────────────────────────────────────
  describe("product name with currency note", () => {
    function buildProductName(
      quotationNumber: string,
      title: string,
      originalCurrency: string,
      total: number,
    ): string {
      const stripeCurrency = getStripeCurrencyPortal(originalCurrency);
      const currencyNote = buildCurrencyNote(
        originalCurrency,
        stripeCurrency,
        total,
      );
      return `Quotation ${quotationNumber} — ${title}${currencyNote}`;
    }

    it("no note when currency is Stripe-supported", () => {
      expect(buildProductName("Q-001", "Web Design", "qar", 5000)).toBe(
        "Quotation Q-001 — Web Design",
      );
    });

    it("appends note when currency falls back to USD", () => {
      expect(buildProductName("Q-002", "Consulting", "OMR", 1509.56)).toBe(
        "Quotation Q-002 — Consulting (OMR 1509.56)",
      );
    });

    it("appends note for BHD currency", () => {
      expect(buildProductName("Q-003", "Service Fee", "BHD", 250)).toBe(
        "Quotation Q-003 — Service Fee (BHD 250.00)",
      );
    });

    it("no note for SAR (supported)", () => {
      expect(buildProductName("Q-004", "Maintenance", "SAR", 1000)).toBe(
        "Quotation Q-004 — Maintenance",
      );
    });
  });

  // ── End-to-end currency flow simulation ────────────────────────────────────
  describe("end-to-end currency flow", () => {
    interface QuotationPayload {
      currency: string;
      total: number;
      quotationNumber: string;
      title: string;
    }

    function simulateStripeLineItem(quotation: QuotationPayload) {
      const origCurrency = quotation.currency || "QAR";
      const stripeCurrency = getStripeCurrencyPortal(origCurrency);
      const currencyNote =
        stripeCurrency !== origCurrency.toLowerCase()
          ? ` (${origCurrency.toUpperCase()} ${quotation.total.toFixed(2)})`
          : "";

      return {
        currency: stripeCurrency,
        productName: `Quotation ${quotation.quotationNumber} — ${quotation.title}${currencyNote}`,
        unitAmount: Math.round(quotation.total * 100),
      };
    }

    it("QAR quotation passes through without note", () => {
      const result = simulateStripeLineItem({
        currency: "QAR",
        total: 5000,
        quotationNumber: "Q-100",
        title: "Logo Design",
      });
      expect(result.currency).toBe("qar");
      expect(result.productName).toBe("Quotation Q-100 — Logo Design");
      expect(result.unitAmount).toBe(500000);
    });

    it("OMR quotation falls back to USD with note", () => {
      const result = simulateStripeLineItem({
        currency: "OMR",
        total: 1509.56,
        quotationNumber: "Q-101",
        title: "Website Build",
      });
      expect(result.currency).toBe("usd");
      expect(result.productName).toBe(
        "Quotation Q-101 — Website Build (OMR 1509.56)",
      );
      expect(result.unitAmount).toBe(150956);
    });

    it("BHD quotation falls back to USD with note", () => {
      const result = simulateStripeLineItem({
        currency: "BHD",
        total: 300,
        quotationNumber: "Q-102",
        title: "Annual Maintenance",
      });
      expect(result.currency).toBe("usd");
      expect(result.productName).toBe(
        "Quotation Q-102 — Annual Maintenance (BHD 300.00)",
      );
      expect(result.unitAmount).toBe(30000);
    });

    it("missing currency defaults to QAR (route applies || 'QAR' guard)", () => {
      // The route handlers apply `quotation.currency || "QAR"` before
      // calling getStripeCurrency, so empty/falsy currency becomes QAR.
      function simulateWithRouteGuard(quotation: QuotationPayload) {
        const guarded = { ...quotation, currency: quotation.currency || "QAR" };
        return simulateStripeLineItem(guarded);
      }

      const result = simulateWithRouteGuard({
        currency: "",
        total: 100,
        quotationNumber: "Q-103",
        title: "Quick Fix",
      });
      expect(result.currency).toBe("qar");
      expect(result.productName).toBe("Quotation Q-103 — Quick Fix");
    });

    it("unit_amount is always integer (no fractional cents)", () => {
      const result = simulateStripeLineItem({
        currency: "USD",
        total: 99.999,
        quotationNumber: "Q-104",
        title: "Test",
      });
      expect(Number.isInteger(result.unitAmount)).toBe(true);
      expect(result.unitAmount).toBe(10000); // Math.round(99.999 * 100) = 10000
    });
  });
});
