import { createHmac, scryptSync, timingSafeEqual } from 'node:crypto';
import type { FastifyRequest, FastifyReply } from 'fastify';
import { config } from '../config.js';
import { extensionAuthService } from '../services/intake.service.js';

function safeCompare(a: string, b: string): boolean {
  const bufA = Buffer.from(a);
  const bufB = Buffer.from(b);
  if (bufA.length !== bufB.length) return false;
  return timingSafeEqual(bufA, bufB);
}

export function verifyAdminPassword(password: string): boolean {
  if (config.adminPasswordHash) {
    const [algo, saltHex, hashHex] = config.adminPasswordHash.split(':');
    if (algo !== 'scrypt' || !saltHex || !hashHex) return false;
    const derived = scryptSync(password, Buffer.from(saltHex, 'hex'), 64);
    const expected = Buffer.from(hashHex, 'hex');
    if (derived.length !== expected.length) return false;
    return timingSafeEqual(derived, expected);
  }
  if (config.adminPassword) {
    return safeCompare(password, config.adminPassword);
  }
  return false;
}

export function extractBearer(request: FastifyRequest): string | null {
  const auth = request.headers.authorization;
  if (!auth?.startsWith('Bearer ')) return null;
  return auth.slice(7);
}

export async function requireMajWpAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {
  const token = extractBearer(request);
  if (!token || !safeCompare(token, config.majWpApiKey)) {
    reply.code(401).send({ error: 'unauthorized', message: 'Invalid or missing API key' });
  }
}

export async function requireExtensionAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {
  const token = extractBearer(request);
  if (!token || !extensionAuthService.validateExtensionToken(token)) {
    reply.code(401).send({ error: 'unauthorized', message: 'Invalid or missing extension token' });
  }
}

export async function requireAdminAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {
  if (!verifySessionCookie(request.cookies.tg_session)) {
    reply.code(401).send({ error: 'unauthorized', message: 'Login required' });
  }
}

function signPayload(payloadB64: string): string {
  return createHmac('sha256', config.sessionSecret).update(payloadB64).digest('base64url');
}

export function createSessionCookie(username: string): string {
  const payload = {
    user: username,
    exp: Date.now() + config.sessionMaxAgeMs,
  };
  const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
  const sig = signPayload(payloadB64);
  return `${payloadB64}.${sig}`;
}

export function verifySessionCookie(session: string | undefined): boolean {
  if (!session) return false;
  const dot = session.lastIndexOf('.');
  if (dot <= 0) return false;
  const payloadB64 = session.slice(0, dot);
  const sig = session.slice(dot + 1);
  if (!safeCompare(signPayload(payloadB64), sig)) return false;
  try {
    const decoded = JSON.parse(Buffer.from(payloadB64, 'base64url').toString());
    return decoded.user === config.adminUsername && decoded.exp >= Date.now();
  } catch {
    return false;
  }
}

export function sessionCookieOptions() {
  return {
    httpOnly: true,
    sameSite: 'lax' as const,
    path: '/',
    maxAge: Math.floor(config.sessionMaxAgeMs / 1000),
    secure: config.isProduction,
  };
}
