/**
 * x402 CRDT payment scheme — server-side verifier.
 *
 * Verifies CRDT payment payloads: JWT signature, DID match,
 * timestamp freshness, and nonce replay protection.
 */

// Lazy-import to avoid pulling EncryptID SDK at module level in shared/
let _verifyToken: ((token: string) => Promise<{ sub: string; did?: string; username?: string }>) | null = null;

export function setTokenVerifier(fn: (token: string) => Promise<{ sub: string; did?: string; username?: string }>) {
  _verifyToken = fn;
}

export interface CrdtPaymentPayload {
  scheme: "crdt";
  jwtToken: string;
  fromDid: string;
  fromLabel?: string;
  amount: number;
  tokenId: string;
  nonce: string;
  timestamp: number;
}

export interface CrdtVerifyResult {
  valid: boolean;
  error?: string;
  fromDid?: string;
  fromLabel?: string;
}

// In-memory nonce store with TTL (sufficient for single-instance deployment)
const usedNonces = new Map<string, number>();
const NONCE_TTL_MS = 10 * 60 * 1000; // 10 minutes
const TIMESTAMP_WINDOW_MS = 5 * 60 * 1000; // 5 minutes

// Cleanup expired nonces every 5 minutes
setInterval(() => {
  const now = Date.now();
  for (const [nonce, ts] of usedNonces) {
    if (now - ts > NONCE_TTL_MS) usedNonces.delete(nonce);
  }
}, 5 * 60 * 1000).unref?.();

/**
 * Verify a CRDT payment payload.
 * Does NOT check balance or execute transfer — that's the middleware's job.
 */
export async function verifyCrdtPayment(
  payload: CrdtPaymentPayload,
  requiredAmount: number,
  requiredTokenId: string,
): Promise<CrdtVerifyResult> {
  // 1. Basic field validation
  if (!payload.jwtToken || !payload.fromDid || !payload.nonce || !payload.timestamp) {
    return { valid: false, error: "Missing required fields" };
  }

  if (payload.tokenId !== requiredTokenId) {
    return { valid: false, error: `Wrong token: expected ${requiredTokenId}, got ${payload.tokenId}` };
  }

  if (payload.amount < requiredAmount) {
    return { valid: false, error: `Insufficient amount: need ${requiredAmount}, got ${payload.amount}` };
  }

  // 2. Timestamp freshness
  const age = Math.abs(Date.now() - payload.timestamp);
  if (age > TIMESTAMP_WINDOW_MS) {
    return { valid: false, error: "Payment timestamp too old or too far in future" };
  }

  // 3. Nonce replay protection
  if (usedNonces.has(payload.nonce)) {
    return { valid: false, error: "Nonce already used (replay detected)" };
  }

  // 4. JWT verification
  if (!_verifyToken) {
    return { valid: false, error: "Token verifier not configured" };
  }

  try {
    const claims = await _verifyToken(payload.jwtToken);
    const claimsDid = (claims.did as string) || `did:key:${(claims.sub as string).slice(0, 32)}`;

    if (claimsDid !== payload.fromDid && claims.sub !== payload.fromDid) {
      return { valid: false, error: "JWT DID does not match payment fromDid" };
    }

    // All checks passed — mark nonce as used
    usedNonces.set(payload.nonce, Date.now());

    return {
      valid: true,
      fromDid: claimsDid,
      fromLabel: payload.fromLabel || claims.username || claimsDid,
    };
  } catch (e) {
    return { valid: false, error: `JWT verification failed: ${(e as Error).message}` };
  }
}
