import assert from "node:assert/strict";
import test from "node:test";

import { createGooglePlayClient } from "./google-play.js";

const PACKAGE_NAME = "com.makecdev.coderemotemanager";
const PRODUCT_ID = "pro_multi_account";
const PURCHASE_TOKEN = "purchase/token+private";

test("purchased unconsumed product is acknowledged and returned as normalized state", async () => {
  const calls = [];
  const client = createClient({
    fetch: async (url, options) => {
      calls.push({ url, options });
      if (options.method === "GET") return json(purchase());
      return new Response(null, { status: 200 });
    },
  });

  assert.deepEqual(await client.verifyPurchase(PURCHASE_TOKEN), {
    state: "purchased",
    acknowledged: true,
    purchaseCompletionTime: "2026-08-02T12:00:00Z",
  });
  assert.equal(calls.length, 2);
  assert.equal(calls[0].url, `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PACKAGE_NAME}/purchases/productsv2/tokens/purchase%2Ftoken%2Bprivate`);
  assert.equal(calls[0].options.method, "GET");
  assert.equal(calls[0].options.headers.get("authorization"), "Bearer adc-access-token");
  assert.equal(calls[1].url, `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PACKAGE_NAME}/purchases/products/${PRODUCT_ID}/tokens/purchase%2Ftoken%2Bprivate:acknowledge`);
  assert.equal(calls[1].options.method, "POST");
  assert.equal(calls[1].options.body, "{}");
});

test("an already acknowledged purchase does not call acknowledgement again", async () => {
  let calls = 0;
  const client = createClient({
    fetch: async () => {
      calls += 1;
      return json(purchase({ acknowledgementState: "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED" }));
    },
  });

  assert.deepEqual(await client.verifyPurchase(PURCHASE_TOKEN), {
    state: "purchased",
    acknowledged: true,
    purchaseCompletionTime: "2026-08-02T12:00:00Z",
  });
  assert.equal(calls, 1);
});

test("pending, canceled, refunded, consumed, and wrong-product purchases fail safely", async (t) => {
  const cases = [
    ["pending", purchase({ purchaseState: "PENDING", purchaseCompletionTime: undefined }), "purchase_pending"],
    ["canceled", purchase({ purchaseState: "CANCELLED" }), "purchase_canceled"],
    ["refunded", purchase({ refundableQuantity: 0 }), "purchase_refunded"],
    ["consumed", purchase({ consumptionState: "CONSUMPTION_STATE_CONSUMED" }), "purchase_consumed"],
    ["wrong product", purchase({ productId: "another_product" }), "purchase_not_valid"],
  ];
  for (const [name, fixture, code] of cases) {
    await t.test(name, async () => {
      let calls = 0;
      const client = createClient({ fetch: async () => { calls += 1; return json(fixture); } });
      await assert.rejects(
        client.verifyPurchase(PURCHASE_TOKEN),
        (error) => error?.code === code && !error.message.includes(PURCHASE_TOKEN)
      );
      assert.equal(calls, 1);
    });
  }
});

test("client rejects a package outside the fixed release allowlist", () => {
  assert.throws(
    () => createGooglePlayClient({
      auth: auth(),
      fetch: async () => json(purchase()),
      packageName: "com.example.another",
      productId: PRODUCT_ID,
    }),
    (error) => error?.code === "invalid_google_play_config"
  );
});

test("acknowledgement conflict is idempotent only after Google confirms acknowledgement", async () => {
  const responses = [
    json(purchase()),
    new Response(null, { status: 409 }),
    json(purchase({ acknowledgementState: "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED" })),
  ];
  const client = createClient({ fetch: async () => responses.shift() });

  assert.deepEqual(await client.verifyPurchase(PURCHASE_TOKEN), {
    state: "purchased",
    acknowledged: true,
    purchaseCompletionTime: "2026-08-02T12:00:00Z",
  });
  assert.equal(responses.length, 0);
});

test("Google lookup and acknowledgement failures expose no upstream body", async (t) => {
  await t.test("lookup", async () => {
    const client = createClient({
      fetch: async () => new Response("Bearer upstream-secret at /private/path", { status: 503 }),
    });
    await assertSafeUnavailable(client.verifyPurchase(PURCHASE_TOKEN));
  });

  await t.test("acknowledgement", async () => {
    const responses = [
      json(purchase()),
      new Response("raw Google failure", { status: 500 }),
    ];
    const client = createClient({ fetch: async () => responses.shift() });
    await assertSafeUnavailable(client.verifyPurchase(PURCHASE_TOKEN));
  });
});

test("a missing or expired Google purchase token is invalid rather than a transient outage", async () => {
  const client = createClient({
    fetch: async () => new Response("private Google not-found detail", { status: 404 }),
  });
  await assert.rejects(client.verifyPurchase(PURCHASE_TOKEN), (error) => {
    assert.equal(error.code, "purchase_not_valid");
    assert.equal(error.status, 400);
    assert.equal(error.message, "The purchase is invalid.");
    assert.equal(JSON.stringify(error).includes("private Google not-found detail"), false);
    return true;
  });
});

function createClient(overrides = {}) {
  return createGooglePlayClient({
    auth: auth(),
    fetch: async () => json(purchase()),
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    ...overrides,
  });
}

function auth() {
  return {
    async getRequestHeaders() {
      return new Headers({ authorization: "Bearer adc-access-token" });
    },
  };
}

function purchase({
  purchaseState = "PURCHASED",
  acknowledgementState = "ACKNOWLEDGEMENT_STATE_PENDING",
  productId = PRODUCT_ID,
  quantity = 1,
  refundableQuantity = 1,
  consumptionState = "CONSUMPTION_STATE_YET_TO_BE_CONSUMED",
  purchaseCompletionTime = "2026-08-02T12:00:00Z",
} = {}) {
  return {
    kind: "androidpublisher#productPurchaseV2",
    productLineItem: [{
      productId,
      productOfferDetails: {
        offerTags: [],
        purchaseOptionId: "buy",
        offerToken: "offer-token",
        quantity,
        refundableQuantity,
        consumptionState,
      },
    }],
    purchaseStateContext: { purchaseState },
    orderId: "GPA.1234-5678-9012-34567",
    regionCode: "KR",
    purchaseCompletionTime,
    acknowledgementState,
  };
}

function json(body, status = 200) {
  return new Response(JSON.stringify(body), {
    status,
    headers: { "content-type": "application/json" },
  });
}

async function assertSafeUnavailable(operation) {
  await assert.rejects(operation, (error) => {
    assert.equal(error.code, "google_play_unavailable");
    assert.equal(error.status, 503);
    assert.equal(error.message, "Google Play verification is unavailable.");
    const serialized = JSON.stringify(error);
    for (const secret of [PURCHASE_TOKEN, "upstream-secret", "/private/path", "raw Google failure"]) {
      assert.equal(serialized.includes(secret), false);
    }
    return true;
  });
}
