import {
  CDNProvider,
  CDNConfig,
  loadCDNConfig,
  checkCDNHealth,
} from "./cdn-config";
import { CloudflareCDNProvider } from "./providers/cloudflare-cdn";

// CDN 서비스 매니저
export class CDNService {
  private provider: CDNProvider | null = null;
  private config: CDNConfig;
  private fallbackEnabled: boolean = true;

  constructor(config?: CDNConfig) {
    this.config = config || loadCDNConfig();
    this.initializeProvider();
  }

  private initializeProvider() {
    if (!this.config.enabled) {
      this.provider = null;
      return;
    }

    switch (this.config.provider) {
      case "cloudflare":
        this.provider = new CloudflareCDNProvider(this.config);
        break;
      case "aws-cloudfront":
        // TODO: AWS CloudFront 프로바이더 구현
        console.warn("AWS CloudFront provider not implemented yet");
        this.provider = null;
        break;
      case "google-cloud-cdn":
        // TODO: Google Cloud CDN 프로바이더 구현
        console.warn("Google Cloud CDN provider not implemented yet");
        this.provider = null;
        break;
      case "azure-cdn":
        // TODO: Azure CDN 프로바이더 구현
        console.warn("Azure CDN provider not implemented yet");
        this.provider = null;
        break;
      default:
        console.error(`Unknown CDN provider: ${this.config.provider}`);
        this.provider = null;
    }
  }

  // CDN 업로드 (폴백 지원)
  async upload(
    file: Buffer,
    key: string,
    mimeType: string
  ): Promise<{
    url: string;
    cdnUrl?: string;
    fallback?: boolean;
  }> {
    if (!this.provider || !this.config.enabled) {
      // CDN이 비활성화되었거나 프로바이더가 없으면 로컬 URL 반환
      return {
        url: `/api/media/files/${key}`,
        fallback: true,
      };
    }

    try {
      const cdnUrl = await this.provider.upload(file, key, mimeType);
      return {
        url: cdnUrl,
        cdnUrl,
        fallback: false,
      };
    } catch (error) {
      console.error("CDN upload failed, using fallback:", error);

      if (this.fallbackEnabled) {
        // 폴백으로 로컬 스토리지 사용
        return {
          url: `/api/media/files/${key}`,
          fallback: true,
        };
      }

      throw error;
    }
  }

  // CDN에서 파일 삭제
  async delete(key: string): Promise<boolean> {
    if (!this.provider || !this.config.enabled) {
      return false;
    }

    try {
      await this.provider.delete(key);
      return true;
    } catch (error) {
      console.error("CDN delete failed:", error);
      return false;
    }
  }

  // CDN 캐시 무효화
  async invalidate(keys: string[]): Promise<boolean> {
    if (!this.provider || !this.config.enabled || keys.length === 0) {
      return false;
    }

    try {
      await this.provider.invalidate(keys);
      return true;
    } catch (error) {
      console.error("CDN invalidation failed:", error);
      return false;
    }
  }

  // URL 생성 (CDN 또는 폴백)
  getUrl(
    key: string,
    options?: {
      forceLocal?: boolean;
      width?: number;
      height?: number;
      format?: string;
      quality?: number;
    }
  ): string {
    if (options?.forceLocal || !this.provider || !this.config.enabled) {
      return `/api/media/files/${key}`;
    }

    let url = this.provider.getUrl(key);

    // 이미지 최적화 옵션이 있으면 적용
    if (options && this.provider instanceof CloudflareCDNProvider) {
      const params = new URLSearchParams();
      if (options.width) params.append("w", options.width.toString());
      if (options.height) params.append("h", options.height.toString());
      if (options.format) params.append("f", options.format);
      if (options.quality) params.append("q", options.quality.toString());

      if (params.toString()) {
        url += `?${params.toString()}`;
      }
    }

    return url;
  }

  // CDN 상태 확인
  async checkHealth(): Promise<{
    healthy: boolean;
    latency?: number;
    error?: string;
    provider: string;
  }> {
    const health = await checkCDNHealth(this.config);
    return {
      ...health,
      provider: this.config.provider,
    };
  }

  // 설정 업데이트
  updateConfig(newConfig: Partial<CDNConfig>) {
    this.config = { ...this.config, ...newConfig };
    this.initializeProvider();
  }

  // 폴백 활성화/비활성화
  setFallbackEnabled(enabled: boolean) {
    this.fallbackEnabled = enabled;
  }

  // 현재 설정 반환
  getConfig(): CDNConfig {
    return { ...this.config };
  }

  // 프로바이더 정보 반환
  getProviderInfo(): {
    name: string;
    enabled: boolean;
    endpoint: string;
    customDomain?: string;
  } {
    return {
      name: this.config.provider,
      enabled: this.config.enabled,
      endpoint: this.config.endpoint,
      customDomain: this.config.customDomain,
    };
  }

  // 캐시 헤더 생성
  getCacheHeaders(mimeType: string): Record<string, string> {
    if (!this.provider) {
      return {};
    }
    return this.provider.getCacheHeaders(mimeType);
  }

  // 배치 작업 (여러 파일 한번에 처리)
  async batchUpload(
    files: Array<{
      buffer: Buffer;
      key: string;
      mimeType: string;
    }>
  ): Promise<
    Array<{
      key: string;
      url: string;
      cdnUrl?: string;
      fallback?: boolean;
      error?: string;
    }>
  > {
    const results = await Promise.allSettled(
      files.map(async ({ buffer, key, mimeType }) => {
        try {
          const result = await this.upload(buffer, key, mimeType);
          return { key, ...result };
        } catch (error) {
          return {
            key,
            url: `/api/media/files/${key}`,
            fallback: true,
            error: error instanceof Error ? error.message : "Unknown error",
          };
        }
      })
    );

    return results.map((result, index) => {
      if (result.status === "fulfilled") {
        return result.value;
      } else {
        return {
          key: files[index].key,
          url: `/api/media/files/${files[index].key}`,
          fallback: true,
          error:
            result.reason instanceof Error
              ? result.reason.message
              : "Upload failed",
        };
      }
    });
  }

  // 배치 삭제
  async batchDelete(keys: string[]): Promise<{
    success: string[];
    failed: string[];
  }> {
    const results = await Promise.allSettled(
      keys.map(async (key) => {
        const success = await this.delete(key);
        return { key, success };
      })
    );

    const success: string[] = [];
    const failed: string[] = [];

    results.forEach((result, index) => {
      const key = keys[index];
      if (result.status === "fulfilled" && result.value.success) {
        success.push(key);
      } else {
        failed.push(key);
      }
    });

    return { success, failed };
  }
}

// 전역 CDN 서비스 인스턴스
let globalCDNService: CDNService | null = null;

export function getCDNService(): CDNService {
  if (!globalCDNService) {
    globalCDNService = new CDNService();
  }
  return globalCDNService;
}

// CDN 서비스 재초기화
export function reinitializeCDNService(config?: CDNConfig): CDNService {
  globalCDNService = new CDNService(config);
  return globalCDNService;
}
