import { createHmac, timingSafeEqual } from 'node:crypto';

/**
 * Verify a Shopify App Bridge session token (a JWT, HS256-signed with the app's
 * client secret) and return the shop domain from its `dest` claim.
 *
 * Hand-rolled (no jsonwebtoken dep): base64url-decode header/payload, recompute
 * the HMAC over "header.payload", timing-safe compare, then validate the
 * standard claims (aud = our API key, exp/nbf window). Returns null on any
 * failure so the caller can fall back to the demo shop rather than throw.
 *
 * Docs: https://shopify.dev/docs/apps/auth/session-tokens
 */
export function verifySessionToken(token: string): { shop: string } | null {
  const debug = process.env.SHOPIFY_DEBUG === '1';
  const fail = (reason: string): null => {
    if (debug) console.warn(`[session-token] rejected: ${reason}`);
    return null;
  };

  const secret = process.env.SHOPIFY_API_SECRET || '';
  const apiKey = process.env.SHOPIFY_API_KEY || '';
  if (!secret || !token) return fail('no secret or token');

  const parts = token.split('.');
  if (parts.length !== 3) return fail(`not a JWT (parts=${parts.length})`);
  const [headerB64, payloadB64, sigB64] = parts;

  // Signature check.
  const expected = createHmac('sha256', secret).update(`${headerB64}.${payloadB64}`).digest();
  const given = b64urlToBuf(sigB64);
  if (!given || given.length !== expected.length || !timingSafeEqual(given, expected)) {
    return fail('signature mismatch (wrong API secret?)');
  }

  // Claims.
  let payload: any;
  try {
    payload = JSON.parse(b64urlToBuf(payloadB64)!.toString('utf8'));
  } catch {
    return fail('bad payload JSON');
  }
  const now = Math.floor(Date.now() / 1000);
  if (typeof payload.exp === 'number' && now >= payload.exp) return fail('expired');
  if (typeof payload.nbf === 'number' && now < payload.nbf - 5) return fail('not yet valid (nbf)');
  if (apiKey && payload.aud && payload.aud !== apiKey) {
    return fail(`aud mismatch (token aud=${payload.aud}, our key=${apiKey})`);
  }

  // dest = "https://shop.myshopify.com"
  const dest = String(payload.dest || '');
  const m = dest.match(/^https:\/\/([a-zA-Z0-9][a-zA-Z0-9-]*\.myshopify\.com)$/);
  if (!m) return fail(`bad dest: ${dest}`);
  if (debug) console.log(`[session-token] OK shop=${m[1]}`);
  return { shop: m[1] };
}

function b64urlToBuf(s: string): Buffer | null {
  try {
    const b64 = s.replace(/-/g, '+').replace(/_/g, '/');
    const pad = b64.length % 4 ? '='.repeat(4 - (b64.length % 4)) : '';
    return Buffer.from(b64 + pad, 'base64');
  } catch {
    return null;
  }
}
