/**
 * In-memory storage provider — for testing and local dev.
 */

import type {
  BlobMeta,
  SignedUrlOptions,
  StorageBucket,
  StorageProvider,
  UploadOptions,
} from '../types.js';

export class MemoryStorageProvider implements StorageProvider {
  private buckets = new Map<string, MemoryBucket>();

  getBucket(name: string): StorageBucket {
    let bucket = this.buckets.get(name);
    if (!bucket) {
      bucket = new MemoryBucket(name);
      this.buckets.set(name, bucket);
    }
    return bucket;
  }

  async isHealthy(): Promise<boolean> {
    return true;
  }

  clear(): void {
    this.buckets.clear();
  }
}

class MemoryBucket implements StorageBucket {
  private blobs = new Map<string, { data: Buffer; meta: BlobMeta }>();

  constructor(private name: string) {}

  async upload(
    key: string,
    data: Buffer | Uint8Array | string,
    options?: UploadOptions
  ): Promise<BlobMeta> {
    const buf = typeof data === 'string' ? Buffer.from(data) : Buffer.from(data);
    const meta: BlobMeta = {
      key,
      size: buf.length,
      contentType: options?.contentType ?? 'application/octet-stream',
      lastModified: new Date(),
      metadata: options?.metadata,
    };
    this.blobs.set(key, { data: buf, meta });
    return meta;
  }

  async download(key: string): Promise<Buffer> {
    const entry = this.blobs.get(key);
    if (!entry) throw new Error(`Blob '${key}' not found in bucket '${this.name}'`);
    return entry.data;
  }

  async delete(key: string): Promise<void> {
    this.blobs.delete(key);
  }

  async exists(key: string): Promise<boolean> {
    return this.blobs.has(key);
  }

  async list(prefix?: string): Promise<BlobMeta[]> {
    const results: BlobMeta[] = [];
    for (const [key, entry] of this.blobs) {
      if (!prefix || key.startsWith(prefix)) {
        results.push(entry.meta);
      }
    }
    return results;
  }

  async getSignedUrl(key: string, _options?: SignedUrlOptions): Promise<string> {
    return `memory://${this.name}/${key}?signed=true`;
  }
}
