/**
 * VPS Provider Abstract Base Class
 * Common interface for Linode, Vultr, and other VPS providers
 */

import type { VPSProviderConfig, CreateServerRequest, CreateServerResponse } from '../types';

export abstract class VPSProviderBase {
  protected config: VPSProviderConfig;

  constructor(config: VPSProviderConfig) {
    this.config = config;
  }

  /**
   * Create a new server instance
   */
  abstract createServer(request: CreateServerRequest): Promise<CreateServerResponse>;

  /**
   * Delete a server instance
   */
  abstract deleteServer(instanceId: string): Promise<{ success: boolean; error?: string }>;

  /**
   * Get server status
   */
  abstract getServerStatus(instanceId: string): Promise<{ status: string; ipv4?: string; ipv6?: string }>;

  /**
   * Map OS image key to provider-specific identifier
   */
  abstract getOsImageId(osImage: string): string;

  /**
   * Fetch with retry and exponential backoff
   */
  protected async fetchWithRetry(
    url: string,
    options: RequestInit,
    retries: number = 3
  ): Promise<Response> {
    let lastError: Error | null = null;

    for (let i = 0; i < retries; i++) {
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);

        const response = await fetch(url, {
          ...options,
          signal: controller.signal,
        });

        clearTimeout(timeoutId);

        // Don't retry on client errors (4xx), only server errors (5xx)
        if (response.ok || (response.status >= 400 && response.status < 500)) {
          return response;
        }

        // Retry on 5xx errors
        if (response.status >= 500 && i < retries - 1) {
          await this.sleep(Math.pow(2, i) * 1000);
          continue;
        }

        return response;
      } catch (error) {
        lastError = error instanceof Error ? error : new Error(String(error));
        if (i === retries - 1) break;
        await this.sleep(Math.pow(2, i) * 1000);
      }
    }

    throw lastError ?? new Error('Max retries exceeded');
  }

  /**
   * Sleep for specified milliseconds
   */
  protected sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  /**
   * Generate cryptographically secure password
   */
  protected generateSecurePassword(length: number = 32): string {
    const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789!@#$%^&*';
    const array = new Uint8Array(length);
    crypto.getRandomValues(array);
    let password = '';
    for (let i = 0; i < length; i++) {
      password += chars[array[i] % chars.length];
    }
    return password;
  }
}

/**
 * OS Image mapping for providers
 */
export const OS_IMAGE_MAP = {
  linode: {
    ubuntu_22_04: 'linode/ubuntu22.04',
    ubuntu_20_04: 'linode/ubuntu20.04',
    debian_11: 'linode/debian11',
    debian_12: 'linode/debian12',
  },
  vultr: {
    ubuntu_22_04: '2284',  // Ubuntu 22.04 x64
    ubuntu_20_04: '1743',  // Ubuntu 20.04 x64
    debian_11: '477',      // Debian 11 x64
    debian_12: '2136',     // Debian 12 x64
  },
} as const;
