import { SignJWT, jwtVerify } from 'jose';
import { db } from '@/lib/db';
import { signingTokens } from '@/lib/db/schema';

const getSecret = () => new TextEncoder().encode(process.env.SIGNING_JWT_SECRET!);

export async function createSigningToken(documentId: string, signerEmail?: string): Promise<{ token: string; jti: string; expiresAt: Date }> {
  const jti = crypto.randomUUID();
  const expiresAt = new Date(Date.now() + 72 * 60 * 60 * 1000); // 72 hours

  const token = await new SignJWT({ documentId, purpose: 'sign' })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('72h')
    .setJti(jti)
    .sign(getSecret());

  // Store token metadata for one-time-use enforcement
  await db.insert(signingTokens).values({
    jti,
    documentId,
    signerEmail: signerEmail ?? null,
    expiresAt,
  });

  return { token, jti, expiresAt };
}

export async function verifySigningToken(token: string): Promise<{ documentId: string; jti: string; exp: number }> {
  // Throws JWTExpired or JWTInvalid on failure — caller handles
  const { payload } = await jwtVerify(token, getSecret());
  return payload as { documentId: string; jti: string; exp: number };
}

// Short-lived download token for client copy download (15-min TTL, no DB record)
// purpose: 'download' claim distinguishes from signing tokens
export async function createDownloadToken(documentId: string): Promise<string> {
  return await new SignJWT({ documentId, purpose: 'download' })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('15m')
    .sign(getSecret());
}

export async function verifyDownloadToken(token: string): Promise<{ documentId: string }> {
  const { payload } = await jwtVerify(token, getSecret());
  if (payload['purpose'] !== 'download') throw new Error('Not a download token');
  return { documentId: payload['documentId'] as string };
}

// Agent download token — purpose: 'agent-download', 5-min TTL, no DB record
// Generated server-side only (server component or API route). Never in a client component.
export async function createAgentDownloadToken(documentId: string): Promise<string> {
  return await new SignJWT({ documentId, purpose: 'agent-download' })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('5m')
    .sign(getSecret());
}

export async function verifyAgentDownloadToken(token: string): Promise<{ documentId: string }> {
  const { payload } = await jwtVerify(token, getSecret());
  if (payload['purpose'] !== 'agent-download') throw new Error('Not an agent download token');
  return { documentId: payload['documentId'] as string };
}

// Signer download token — purpose: 'signer-download', 72h TTL, no DB record
// Sent to signers on completion so they can download the fully signed PDF.
export async function createSignerDownloadToken(documentId: string): Promise<string> {
  return await new SignJWT({ documentId, purpose: 'signer-download' })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('72h')
    .sign(getSecret());
}

export async function verifySignerDownloadToken(token: string): Promise<{ documentId: string }> {
  const { payload } = await jwtVerify(token, getSecret());
  if (payload['purpose'] !== 'signer-download') throw new Error('Not a signer download token');
  return { documentId: payload['documentId'] as string };
}
