import crypto from 'crypto';
import { buildCanonicalRequest, presignGetObjectUrl } from '../../../utils/r2Presigner';

// Known-good AWS SigV4 query-string authentication example.
// https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
const AWS_EXAMPLE = {
  accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
  secretAccessKey: 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
  endpoint: 'https://examplebucket.s3.amazonaws.com',
  region: 'us-east-1',
  bucket: '',
  objectKey: 'test.txt',
  expiresIn: 86400,
  now: new Date('2013-05-24T00:00:00Z'),
};

describe('presignGetObjectUrl', () => {
  it('matches the published AWS SigV4 query-string example', () => {
    const url = presignGetObjectUrl(AWS_EXAMPLE);
    const parsed = new URL(url);

    expect(parsed.searchParams.get('X-Amz-Algorithm')).toBe('AWS4-HMAC-SHA256');
    expect(parsed.searchParams.get('X-Amz-Credential')).toBe(
      'AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request'
    );
    expect(parsed.searchParams.get('X-Amz-Date')).toBe('20130524T000000Z');
    expect(parsed.searchParams.get('X-Amz-Expires')).toBe('86400');
    expect(parsed.searchParams.get('X-Amz-SignedHeaders')).toBe('host');
    expect(parsed.searchParams.get('X-Amz-Signature')).toMatch(/^[0-9a-f]{64}$/);
  });

  // AWS publishes this canonical-request digest for the example above. It is the
  // external anchor: matching it proves the canonicalization, not just self-consistency.
  it('canonicalizes exactly as AWS documents for that example', () => {
    const { canonicalRequest } = buildCanonicalRequest(AWS_EXAMPLE);

    expect(crypto.createHash('sha256').update(canonicalRequest).digest('hex')).toBe(
      '3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04'
    );
  });

  it('derives the documented signature from that canonical request', () => {
    expect(new URL(presignGetObjectUrl(AWS_EXAMPLE)).searchParams.get('X-Amz-Signature')).toBe(
      '3ed0be64024db54d5574a27da223529635c383f911f80e636f0ccc13890053d2'
    );
  });

  it('signs a bucket-scoped R2 object key without leaking credentials', () => {
    const url = presignGetObjectUrl({
      ...AWS_EXAMPLE,
      endpoint: 'https://account.r2.cloudflarestorage.com',
      bucket: 'press-zone-releases',
      objectKey: 'international-press-zone/1.4.0/international-press-zone.zip',
      expiresIn: 300,
    });
    const parsed = new URL(url);

    expect(parsed.pathname).toBe(
      '/press-zone-releases/international-press-zone/1.4.0/international-press-zone.zip'
    );
    expect(parsed.searchParams.get('X-Amz-Expires')).toBe('300');
    expect(url).not.toContain(AWS_EXAMPLE.secretAccessKey);
  });

  it('produces a different signature for a different object key', () => {
    const a = presignGetObjectUrl({ ...AWS_EXAMPLE, objectKey: 'a.zip' });
    const b = presignGetObjectUrl({ ...AWS_EXAMPLE, objectKey: 'b.zip' });

    expect(new URL(a).searchParams.get('X-Amz-Signature')).not.toBe(
      new URL(b).searchParams.get('X-Amz-Signature')
    );
  });
});
