import { StorageService } from './StorageService';
import { MinioStorageService } from './MinioStorageService';

export class StorageFactory {
  private static instance: StorageService | null = null;
  private static initializationPromise: Promise<StorageService> | null = null;

  static async getInstance(): Promise<StorageService> {
    if (this.instance) {
      return this.instance;
    }

    if (this.initializationPromise) {
      return await this.initializationPromise;
    }

    this.initializationPromise = this.createStorageServiceWithRetry();

    try {
      this.instance = await this.initializationPromise;
      return this.instance;
    } catch (error) {
      this.initializationPromise = null;
      throw error;
    }
  }

  static getInstanceSync(): StorageService {
    if (!this.instance) {
      try {
        this.instance = this.createStorageService();
      } catch (error) {
        throw new Error('Storage service unavailable. Please check MinIO configuration.');
      }
    }
    return this.instance;
  }

  private static async createStorageServiceWithRetry(): Promise<StorageService> {
    const maxRetries = 3;
    const baseDelay = 1000; // 1 second

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        const service = this.createStorageService();

        await service.bucketExists();

        return service;
      } catch (error) {
        if (attempt === maxRetries) {
          throw new Error(
            `Failed to initialize storage service after ${maxRetries} attempts. ` +
              `Last error: ${error instanceof Error ? error.message : 'Unknown error'}`,
          );
        }

        const delay = baseDelay * Math.pow(2, attempt - 1);
        await this.sleep(delay);
      }
    }

    throw new Error('Unexpected error in storage service creation');
  }

  private static sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  private static createStorageService(): StorageService {
    const storageType = process.env['STORAGE_TYPE'] || 'minio';

    try {
      switch (storageType.toLowerCase()) {
        case 'minio': {
          const endpoint = process.env['MINIO_ENDPOINT'];
          const accessKey = process.env['MINIO_ACCESS_KEY'];
          const secretKey = process.env['MINIO_SECRET_KEY'];
          const useSSL = process.env['MINIO_USE_SSL'] === 'true';
          const bucketName = process.env['MINIO_BUCKET_NAME'] || 'banatie';
          const publicUrl = process.env['MINIO_PUBLIC_URL'];

          console.log(`[StorageFactory] Creating MinIO client with endpoint: ${endpoint}`);

          if (!endpoint || !accessKey || !secretKey) {
            throw new Error(
              'MinIO configuration missing. Required: MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY',
            );
          }

          return new MinioStorageService(
            endpoint,
            accessKey,
            secretKey,
            useSSL,
            bucketName,
            publicUrl,
          );
        }

        default:
          throw new Error(`Unsupported storage type: ${storageType}`);
      }
    } catch (error) {
      throw error;
    }
  }

  static resetInstance(): void {
    this.instance = null;
    this.initializationPromise = null;
  }
}
