import { NextRequest, NextResponse } from "next/server";

// TOTP implementation (RFC 6238)
function hotp(key: Uint8Array, counter: bigint): number {
  // We'll use Node.js crypto
  const crypto = require("crypto");
  const buf = Buffer.alloc(8);
  buf.writeBigUInt64BE(counter);
  const hmac = crypto.createHmac("sha1", key);
  hmac.update(buf);
  const hash: Buffer = hmac.digest();
  const offset = hash[hash.length - 1] & 0x0f;
  const code =
    ((hash[offset] & 0x7f) << 24) |
    ((hash[offset + 1] & 0xff) << 16) |
    ((hash[offset + 2] & 0xff) << 8) |
    (hash[offset + 3] & 0xff);
  return code % 1_000_000;
}

function base32Decode(input: string): Uint8Array {
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  const clean = input.toUpperCase().replace(/=+$/, "").replace(/\s/g, "");
  let bits = 0;
  let value = 0;
  const output: number[] = [];

  for (const char of clean) {
    const idx = alphabet.indexOf(char);
    if (idx === -1) throw new Error(`Invalid base32 character: ${char}`);
    value = (value << 5) | idx;
    bits += 5;
    if (bits >= 8) {
      output.push((value >>> (bits - 8)) & 0xff);
      bits -= 8;
    }
  }
  return new Uint8Array(output);
}

export async function GET(req: NextRequest) {
  const secret = req.nextUrl.searchParams.get("secret")?.trim();
  if (!secret) return NextResponse.json({ error: "secret required" }, { status: 400 });

  try {
    const key = base32Decode(secret);
    const now = Math.floor(Date.now() / 1000);
    const step = 30;
    const counter = BigInt(Math.floor(now / step));
    const remaining = step - (now % step);

    const current = hotp(key, counter).toString().padStart(6, "0");
    const previous = hotp(key, counter - 1n).toString().padStart(6, "0");
    const next = hotp(key, counter + 1n).toString().padStart(6, "0");

    return NextResponse.json({
      current,
      previous,
      next,
      remaining,
      step,
      timestamp: now,
    });
  } catch (err: unknown) {
    const msg = err instanceof Error ? err.message : "failed";
    return NextResponse.json({ error: msg }, { status: 400 });
  }
}
