/**
 * Security tests for POST /api/quotations/portal/[token]/pay
 * Verifies successUrl and cancelUrl are validated against NEXT_PUBLIC_APP_URL
 */

jest.mock("@/lib/services/quotation-portal.service", () => ({
  createPortalCheckoutSession: jest.fn(),
}));
jest.mock("@/lib/data-source", () => ({
  getDataSource: jest.fn(() => "prisma"),
}));

import { NextRequest } from "next/server";
import * as portalService from "@/lib/services/quotation-portal.service";

const APP_URL = "https://app.mawidi.com";

function makeReq(body: Record<string, unknown>) {
  return new NextRequest(
    "http://localhost:9000/api/quotations/portal/valid-token-abc123456/pay",
    {
      method: "POST",
      body: JSON.stringify(body),
      headers: { "Content-Type": "application/json" },
    },
  );
}

const makeParams = (token: string) => Promise.resolve({ token });

describe("POST /api/quotations/portal/[token]/pay — open redirect prevention", () => {
  let mod: typeof import("@/app/api/quotations/portal/[token]/pay/route");

  beforeAll(async () => {
    process.env.NEXT_PUBLIC_APP_URL = APP_URL;
    mod = await import("@/app/api/quotations/portal/[token]/pay/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("rejects successUrl pointing to external domain", async () => {
    const res = await mod.POST(
      makeReq({
        successUrl: "https://attacker.com/steal",
        cancelUrl: `${APP_URL}/quotation/valid-token-abc123456`,
      }),
      { params: makeParams("valid-token-abc123456") },
    );
    expect(res.status).toBe(400);
    const json = await res.json();
    expect(json.success).toBe(false);
    expect(portalService.createPortalCheckoutSession).not.toHaveBeenCalled();
  });

  it("rejects cancelUrl pointing to external domain", async () => {
    const res = await mod.POST(
      makeReq({
        successUrl: `${APP_URL}/quotation/valid-token-abc123456/success`,
        cancelUrl: "https://evil.com/phish",
      }),
      { params: makeParams("valid-token-abc123456") },
    );
    expect(res.status).toBe(400);
    const json = await res.json();
    expect(json.success).toBe(false);
    expect(portalService.createPortalCheckoutSession).not.toHaveBeenCalled();
  });

  it("rejects javascript: protocol in successUrl", async () => {
    const res = await mod.POST(
      makeReq({
        successUrl: "javascript:alert(1)",
        cancelUrl: `${APP_URL}/quotation/valid-token-abc123456`,
      }),
      { params: makeParams("valid-token-abc123456") },
    );
    expect(res.status).toBe(400);
  });

  it("allows valid same-origin successUrl and cancelUrl", async () => {
    (portalService.createPortalCheckoutSession as jest.Mock).mockResolvedValue({
      success: true,
      checkoutUrl: "https://checkout.stripe.com/pay/test_session_123",
    });

    const res = await mod.POST(
      makeReq({
        successUrl: `${APP_URL}/quotation/valid-token-abc123456/success`,
        cancelUrl: `${APP_URL}/quotation/valid-token-abc123456`,
      }),
      { params: makeParams("valid-token-abc123456") },
    );
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(portalService.createPortalCheckoutSession).toHaveBeenCalled();
  });
});
