import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { setStorage, MemoryStorageProvider } from '@bytelyst/storage';

import {
  _resetBlobClient,
  generateSasUrl,
  getBucket,
  getStorageProvider,
  isBlobStorageConfigured,
  BLOB_CONTAINERS,
} from '../index.js';

describe('blob', () => {
  beforeEach(() => {
    _resetBlobClient();
    delete process.env.AZURE_BLOB_CONNECTION_STRING;
    delete process.env.AZURE_BLOB_ACCOUNT_NAME;
    delete process.env.AZURE_BLOB_ACCOUNT_KEY;
    delete process.env.STORAGE_PROVIDER;
  });

  afterEach(() => {
    _resetBlobClient();
    delete process.env.AZURE_BLOB_CONNECTION_STRING;
    delete process.env.AZURE_BLOB_ACCOUNT_NAME;
    delete process.env.AZURE_BLOB_ACCOUNT_KEY;
    delete process.env.STORAGE_PROVIDER;
  });

  describe('isBlobStorageConfigured', () => {
    it('is false when unset', () => {
      expect(isBlobStorageConfigured()).toBe(false);
    });

    it('is true when connection string is set', () => {
      process.env.AZURE_BLOB_CONNECTION_STRING = 'AccountName=x;AccountKey=y;';
      expect(isBlobStorageConfigured()).toBe(true);
    });

    it('is true when account name + key are set', () => {
      process.env.AZURE_BLOB_ACCOUNT_NAME = 'acc';
      process.env.AZURE_BLOB_ACCOUNT_KEY = 'key==';
      expect(isBlobStorageConfigured()).toBe(true);
    });

    it('is true when provider is memory', () => {
      process.env.STORAGE_PROVIDER = 'memory';
      expect(isBlobStorageConfigured()).toBe(true);
    });
  });

  describe('with memory provider', () => {
    let memoryProvider: MemoryStorageProvider;

    beforeEach(() => {
      memoryProvider = new MemoryStorageProvider();
      setStorage(memoryProvider);
    });

    it('getStorageProvider returns the provider', async () => {
      const provider = await getStorageProvider();
      expect(provider).toBe(memoryProvider);
    });

    it('getBucket returns a bucket by name', async () => {
      const bucket = await getBucket('audio');
      expect(bucket).toBeDefined();
      // Upload and download to verify it works
      await bucket.upload('test.wav', Buffer.from('hello'));
      const data = await bucket.download('test.wav');
      expect(data.toString()).toBe('hello');
    });

    it('generateSasUrl returns a signed URL', async () => {
      const url = await generateSasUrl('audio', 'path/file.wav', 'r', 10);
      expect(url).toContain('audio');
      expect(url).toContain('path/file.wav');
      expect(url).toContain('signed=true');
    });

    it('generateSasUrl defaults to read permissions', async () => {
      const url = await generateSasUrl('audio', 'file.wav');
      expect(url).toContain('signed=true');
    });

    it('_resetBlobClient resets the storage singleton', async () => {
      const p1 = await getStorageProvider();
      _resetBlobClient();
      // After reset, inject a new provider
      const newProvider = new MemoryStorageProvider();
      setStorage(newProvider);
      const p2 = await getStorageProvider();
      expect(p1).not.toBe(p2);
    });
  });

  describe('BLOB_CONTAINERS', () => {
    it('has expected container names', () => {
      expect(BLOB_CONTAINERS.audio).toBe('audio');
      expect(BLOB_CONTAINERS.transcripts).toBe('transcripts');
      expect(BLOB_CONTAINERS.attachments).toBe('attachments');
      expect(BLOB_CONTAINERS.avatars).toBe('avatars');
      expect(BLOB_CONTAINERS.releases).toBe('releases');
      expect(BLOB_CONTAINERS.backups).toBe('backups');
      expect(BLOB_CONTAINERS.feedbackScreenshots).toBe('feedback-screenshots');
    });
  });
});
