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

import { createPurchaseStateStore, hashPurchaseToken } from "./purchase-state.js";

const PACKAGE_NAME = "com.makecdev.coderemotemanager";
const PRODUCT_ID = "pro_multi_account";
const PURCHASE_TOKEN = "raw-purchase-token";
const PURCHASE_KEY = "c6faff8423a856e848b1a06138b9bef3fa258bcf40ec1167b116ba771a849ca6";
const NOW = Date.UTC(2026, 7, 2, 12, 0, 0);

test("purchase key is the exact SHA-256 tuple and active writes never retain the token", async () => {
  assert.equal(hashPurchaseToken({
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    purchaseToken: PURCHASE_TOKEN,
  }), PURCHASE_KEY);

  const memory = fakeFirestore();
  const store = createPurchaseStateStore({ firestore: memory.firestore, now: () => NOW });
  const input = {
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    purchaseToken: PURCHASE_TOKEN,
    purchaseCompletionTime: "2026-08-02T11:55:00Z",
  };

  assert.deepEqual(await store.recordActive(input), { purchaseKey: PURCHASE_KEY, state: "active" });
  assert.deepEqual(await store.recordActive(input), { purchaseKey: PURCHASE_KEY, state: "active" });
  assert.deepEqual([...memory.docs.keys()], [`purchases/${PURCHASE_KEY}`]);
  assert.deepEqual(memory.docs.get(`purchases/${PURCHASE_KEY}`), {
    schemaVersion: 1,
    state: "active",
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    purchaseCompletionTime: "2026-08-02T11:55:00Z",
    createdAt: new Date(NOW),
    lastVerifiedAt: new Date(NOW),
  });
  assert.equal(JSON.stringify([...memory.docs]).includes(PURCHASE_TOKEN), false);
  assert.equal(JSON.stringify(memory.writes).includes(PURCHASE_TOKEN), false);
});

test("invalidation is idempotent, retains minimum audit state for 180 days, and blocks issuance", async () => {
  const memory = fakeFirestore();
  const store = createPurchaseStateStore({ firestore: memory.firestore, now: () => NOW });
  const identity = { packageName: PACKAGE_NAME, productId: PRODUCT_ID, purchaseToken: PURCHASE_TOKEN };
  await store.recordActive({ ...identity, purchaseCompletionTime: "2026-08-02T11:55:00Z" });

  assert.deepEqual(await store.invalidate({ ...identity, reason: "refunded" }), {
    purchaseKey: PURCHASE_KEY,
    state: "invalidated",
  });
  assert.deepEqual(await store.invalidate({ ...identity, reason: "canceled" }), {
    purchaseKey: PURCHASE_KEY,
    state: "invalidated",
  });
  assert.deepEqual(memory.docs.get(`purchases/${PURCHASE_KEY}`), {
    schemaVersion: 1,
    state: "invalidated",
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    invalidatedAt: new Date(NOW),
    invalidationReason: "refunded",
    deleteAfter: new Date(NOW + (180 * 24 * 60 * 60 * 1000)),
  });
  await assert.rejects(
    store.recordActive({ ...identity, purchaseCompletionTime: "2026-08-02T11:55:00Z" }),
    (error) => error?.code === "purchase_invalidated" && error?.status === 402
  );
  assert.equal(JSON.stringify([...memory.docs]).includes(PURCHASE_TOKEN), false);
});

test("an invalidation arriving before verification still blocks later issuance", async () => {
  const memory = fakeFirestore();
  const store = createPurchaseStateStore({ firestore: memory.firestore, now: () => NOW });
  const identity = { packageName: PACKAGE_NAME, productId: PRODUCT_ID, purchaseToken: PURCHASE_TOKEN };

  await store.invalidate({ ...identity, reason: "voided" });
  await assert.rejects(
    store.recordActive({ ...identity, purchaseCompletionTime: "2026-08-02T11:55:00Z" }),
    (error) => error?.code === "purchase_invalidated"
  );
});

test("unexpected persisted state fails closed without exposing its contents", async () => {
  const memory = fakeFirestore();
  memory.docs.set(`purchases/${PURCHASE_KEY}`, { state: "active", purchaseToken: PURCHASE_TOKEN });
  const store = createPurchaseStateStore({ firestore: memory.firestore, now: () => NOW });

  await assert.rejects(store.recordActive({
    packageName: PACKAGE_NAME,
    productId: PRODUCT_ID,
    purchaseToken: PURCHASE_TOKEN,
    purchaseCompletionTime: "2026-08-02T11:55:00Z",
  }), (error) => {
    assert.equal(error.code, "purchase_state_invalid");
    assert.equal(JSON.stringify(error).includes(PURCHASE_TOKEN), false);
    return true;
  });
});

function fakeFirestore() {
  const docs = new Map();
  const writes = [];
  let queue = Promise.resolve();
  const firestore = {
    collection(name) {
      assert.equal(name, "purchases");
      return {
        doc(id) {
          return { path: `${name}/${id}` };
        },
      };
    },
    runTransaction(operation) {
      const run = queue.then(async () => {
        const pending = [];
        const transaction = {
          async get(reference) {
            const value = docs.get(reference.path);
            return { exists: value !== undefined, data: () => structuredClone(value) };
          },
          set(reference, value) {
            pending.push([reference.path, structuredClone(value)]);
          },
        };
        const result = await operation(transaction);
        for (const [path, value] of pending) {
          docs.set(path, value);
          writes.push([path, value]);
        }
        return result;
      });
      queue = run.catch(() => {});
      return run;
    },
  };
  return { docs, firestore, writes };
}
