import { Test, TestingModule } from '@nestjs/testing';
import { S3 } from 'aws-sdk';
import { EEnvVariable } from '../../../configuration/enums/env-variable.enum';
import { S3Service } from './s3.service';

describe('S3Service', () => {
  // AWS S3 parameters
  const region = 'aws-region';
  const accessKeyId = 'aws-access-key-id';
  const secretAccessKey = 'aws-secret-access-key';
  const bucket = 'aws-bucket';

  let service: S3Service;

  beforeEach(async () => {
    // Set environment variables
    process.env[EEnvVariable.AMAZON_REGION] = region;
    process.env[EEnvVariable.AMAZON_ACCESS_KEY_ID] = accessKeyId;
    process.env[EEnvVariable.AMAZON_SECRET_ACCESS_KEY] = secretAccessKey;
    process.env[EEnvVariable.AMAZON_BUCKET] = bucket;

    const module: TestingModule = await Test.createTestingModule({
      providers: [S3Service],
    }).compile();

    service = module.get<S3Service>(S3Service);

    // Mock aws-sdk functions
    service.s3.getObject = jest.fn();
    service.s3.headObject = jest.fn();
    service.s3.upload = jest.fn();
    service.s3.deleteObject = jest.fn();
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('should create valid S3 aws-sdk object', () => {
    expect(service.s3).toBeDefined();
    expect(service.s3).toBeInstanceOf(S3);
    expect(service.s3.config.region).toBe(region);
    expect(service.s3.config.accessKeyId).toBe(accessKeyId);
    expect(service.s3.config.secretAccessKey).toBe(secretAccessKey);
  });

  it('getObject should call S3.getObject', () => {
    const key = 'key';

    service.getObject(key);

    expect(service.s3.getObject).toHaveBeenNthCalledWith(1, {
      Bucket: bucket,
      Key: key,
    });
  });

  it('headObject should call S3.headObject', () => {
    const key = 'key';

    service.headObject(key);

    expect(service.s3.headObject).toHaveBeenNthCalledWith(1, {
      Bucket: bucket,
      Key: key,
    });
  });

  it('upload should call S3.upload', () => {
    const key = 'key';
    const body = 'body';

    service.upload(key, body);

    expect(service.s3.upload).toHaveBeenNthCalledWith(1, {
      Bucket: bucket,
      Key: key,
      Body: body,
    });
  });

  it('deleteObject should call S3.deleteObject', () => {
    const key = 'key';

    service.deleteObject(key);

    expect(service.s3.deleteObject).toHaveBeenNthCalledWith(1, {
      Bucket: bucket,
      Key: key,
    });
  });
});
