/**
 * AWS Signature Version 4 Signing
 * Implements AWS request signing for S3 uploads
 */

/**
 * Create AWS Signature V4 for S3 PUT request
 */
export async function signS3Request({ method, url, headers, payload, credentials }) {
  const { accessKeyId, secretAccessKey, sessionToken, region } = credentials;

  // Parse URL
  const urlObj = new URL(url);
  const host = urlObj.hostname;
  const path = urlObj.pathname;

  // Get current date/time
  const now = new Date();
  const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, ''); // YYYYMMDDTHHMMSSZ
  const dateStamp = amzDate.substring(0, 8); // YYYYMMDD

  // Create canonical request
  const canonicalHeaders = `host:${host}\nx-amz-content-sha256:UNSIGNED-PAYLOAD\nx-amz-date:${amzDate}\nx-amz-security-token:${sessionToken}\n`;
  const signedHeaders = 'host;x-amz-content-sha256;x-amz-date;x-amz-security-token';

  const canonicalRequest = [
    method,
    path,
    '', // query string (empty for PUT)
    canonicalHeaders,
    signedHeaders,
    'UNSIGNED-PAYLOAD' // for streaming uploads we use UNSIGNED-PAYLOAD
  ].join('\n');

  console.log('[AWS Signature] Canonical request:', canonicalRequest);

  // Create string to sign
  const algorithm = 'AWS4-HMAC-SHA256';
  const credentialScope = `${dateStamp}/${region}/s3/aws4_request`;

  const canonicalRequestHash = await sha256(canonicalRequest);

  const stringToSign = [
    algorithm,
    amzDate,
    credentialScope,
    canonicalRequestHash
  ].join('\n');

  console.log('[AWS Signature] String to sign:', stringToSign);

  // Calculate signature
  const signingKey = await getSignatureKey(secretAccessKey, dateStamp, region, 's3');
  const signature = await hmacSha256(stringToSign, signingKey, 'hex');

  console.log('[AWS Signature] Signature:', signature);

  // Create authorization header
  const authorization = `${algorithm} Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;

  // Return signed headers
  return {
    'Authorization': authorization,
    'x-amz-date': amzDate,
    'x-amz-content-sha256': 'UNSIGNED-PAYLOAD',
    'x-amz-security-token': sessionToken,
    ...headers
  };
}

/**
 * Get AWS Signature V4 signing key
 */
async function getSignatureKey(key, dateStamp, regionName, serviceName) {
  const kDate = await hmacSha256(dateStamp, 'AWS4' + key);
  const kRegion = await hmacSha256(regionName, kDate);
  const kService = await hmacSha256(serviceName, kRegion);
  const kSigning = await hmacSha256('aws4_request', kService);
  return kSigning;
}

/**
 * SHA256 hash
 */
async function sha256(message) {
  const encoder = new TextEncoder();
  const data = encoder.encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return bufferToHex(hashBuffer);
}

/**
 * HMAC-SHA256
 */
async function hmacSha256(message, key, encoding = null) {
  const encoder = new TextEncoder();

  // If key is a string, convert to bytes
  const keyData = typeof key === 'string' ? encoder.encode(key) : key;

  // Import key
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    keyData,
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );

  // Sign message
  const messageData = encoder.encode(message);
  const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);

  // Return as hex string or raw bytes
  if (encoding === 'hex') {
    return bufferToHex(signature);
  }
  return new Uint8Array(signature);
}

/**
 * Convert ArrayBuffer to hex string
 */
function bufferToHex(buffer) {
  return Array.from(new Uint8Array(buffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}
