/**
 * Tests for MemoryStorageProvider.
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { MemoryStorageProvider } from '../providers/memory.js';
import type { StorageBucket } from '../types.js';

describe('MemoryStorageProvider', () => {
  let provider: MemoryStorageProvider;
  let bucket: StorageBucket;

  beforeEach(() => {
    provider = new MemoryStorageProvider();
    bucket = provider.getBucket('test-bucket');
  });

  it('isHealthy returns true', async () => {
    expect(await provider.isHealthy()).toBe(true);
  });

  it('returns same bucket instance', () => {
    const b1 = provider.getBucket('x');
    const b2 = provider.getBucket('x');
    expect(b1).toBe(b2);
  });

  describe('bucket operations', () => {
    it('upload + download', async () => {
      await bucket.upload('file.txt', 'hello world', { contentType: 'text/plain' });
      const data = await bucket.download('file.txt');
      expect(data.toString()).toBe('hello world');
    });

    it('upload returns metadata', async () => {
      const meta = await bucket.upload('file.txt', Buffer.from('test'), {
        contentType: 'text/plain',
        metadata: { foo: 'bar' },
      });
      expect(meta.key).toBe('file.txt');
      expect(meta.size).toBe(4);
      expect(meta.contentType).toBe('text/plain');
      expect(meta.metadata?.foo).toBe('bar');
    });

    it('download throws for missing blob', async () => {
      await expect(bucket.download('missing')).rejects.toThrow('not found');
    });

    it('exists returns true/false', async () => {
      expect(await bucket.exists('file.txt')).toBe(false);
      await bucket.upload('file.txt', 'data');
      expect(await bucket.exists('file.txt')).toBe(true);
    });

    it('delete removes blob', async () => {
      await bucket.upload('file.txt', 'data');
      await bucket.delete('file.txt');
      expect(await bucket.exists('file.txt')).toBe(false);
    });

    it('list returns all blobs', async () => {
      await bucket.upload('a/1.txt', 'data');
      await bucket.upload('a/2.txt', 'data');
      await bucket.upload('b/1.txt', 'data');

      const all = await bucket.list();
      expect(all).toHaveLength(3);

      const prefixed = await bucket.list('a/');
      expect(prefixed).toHaveLength(2);
    });

    it('getSignedUrl returns memory URL', async () => {
      const url = await bucket.getSignedUrl('file.txt');
      expect(url).toContain('memory://');
      expect(url).toContain('file.txt');
    });
  });
});
