import crypto from 'crypto';

/**
 * Checksum length in hex characters (16 chars = 64 bits of entropy)
 */
export const CHECKSUM_LENGTH = 16;

/**
 * Generate share link checksum for location
 * Uses HMAC-SHA256 for cryptographic integrity
 *
 * SECURITY: Prevents location ID enumeration while allowing stateless validation
 */
export function generateShareChecksum(locationId: string): string {
  const secret = process.env.SHARE_LINK_SECRET;

  if (!secret) {
    throw new Error('SHARE_LINK_SECRET environment variable not configured');
  }

  return crypto
    .createHmac('sha256', secret)
    .update(locationId)
    .digest('hex')
    .substring(0, CHECKSUM_LENGTH);
}

/**
 * Validate share link checksum
 * Uses constant-time comparison to prevent timing attacks
 *
 * @param locationId - The location ID from URL
 * @param providedChecksum - The checksum from URL
 * @returns true if checksum is valid
 */
export function validateShareChecksum(
  locationId: string,
  providedChecksum: string
): boolean {
  try {
    const expectedChecksum = generateShareChecksum(locationId);

    // Convert to buffers for timing-safe comparison
    const expected = Buffer.from(expectedChecksum);
    const provided = Buffer.from(providedChecksum);

    // Length check (prevents timing attack on different lengths)
    if (expected.length !== provided.length) {
      return false;
    }

    // Constant-time comparison (prevents timing attacks)
    return crypto.timingSafeEqual(expected, provided);
  } catch {
    return false;
  }
}

/**
 * Generate combined location ID with checksum appended
 * @param locationId - The MongoDB location ID (24 chars)
 * @returns Combined ID: locationId + checksum (40 chars total)
 */
export function generateShareId(locationId: string): string {
  const checksum = generateShareChecksum(locationId);
  return locationId + checksum;
}

/**
 * Extract location ID and checksum from combined share ID
 * @param shareId - Combined ID (locationId + checksum)
 * @returns Object with locationId and checksum, or null if invalid format
 */
export function extractShareId(shareId: string): { locationId: string; checksum: string } | null {
  // MongoDB ObjectID is 24 chars, checksum is 16 chars = 40 total
  const expectedLength = 24 + CHECKSUM_LENGTH;

  if (shareId.length !== expectedLength) {
    return null;
  }

  const locationId = shareId.substring(0, 24);
  const checksum = shareId.substring(24);

  return { locationId, checksum };
}
