import * as plugins from './cloudflare.plugins.js';
import { CloudflareAccount } from './cloudflare.classes.account.js';
import { CloudflareWorker } from './cloudflare.classes.worker.js';
import { logger } from './cloudflare.logger.js';

export class WorkerManager {
  public cfAccount: CloudflareAccount;

  constructor(cfAccountArg: CloudflareAccount) {
    this.cfAccount = cfAccountArg;
  }

  /**
   * Creates a new worker or updates an existing one
   * @param workerName Name of the worker
   * @param workerScript JavaScript content of the worker
   * @returns CloudflareWorker instance for the created/updated worker
   */
  public async createWorker(workerName: string, workerScript: string): Promise<CloudflareWorker> {
    if (!this.cfAccount.preselectedAccountId) {
      throw new Error('No account selected. Please select it first on the account.');
    }
    
    try {
      // Use the official client to create/update the worker
      await this.cfAccount.apiAccount.workers.scripts.content.update(workerName, {
        account_id: this.cfAccount.preselectedAccountId,
        "CF-WORKER-BODY-PART": workerScript,
        metadata: {}
      });
      
      // Create a new worker instance
      const worker = new CloudflareWorker(this);
      worker.id = workerName;
      worker.script = workerScript;
      
      // Initialize the worker and get its routes
      try {
        await worker.getRoutes();
      } catch (routeError) {
        logger.log('warn', `Failed to get routes for worker ${workerName}: ${routeError.message}`);
        // Continue anyway since the worker was created
      }
      
      return worker;
    } catch (error) {
      logger.log('error', `Failed to create worker ${workerName}: ${error.message}`);
      throw error;
    }
  }

  /**
   * Get a worker by name
   * @param workerName Name of the worker to retrieve
   * @returns CloudflareWorker instance or undefined if not found
   */
  public async getWorker(workerName: string): Promise<CloudflareWorker | undefined> {
    if (!this.cfAccount.preselectedAccountId) {
      throw new Error('No account selected. Please select it first on the account.');
    }
    
    try {
      // Get the worker script using the official client
      const workerScript = await this.cfAccount.apiAccount.workers.scripts.get(workerName, {
        account_id: this.cfAccount.preselectedAccountId
      });
      
      // Create a new worker instance
      const worker = new CloudflareWorker(this);
      worker.id = workerName;
      
      // Save script content if available
      if (workerScript && typeof workerScript === 'object') {
        Object.assign(worker, workerScript);
      }
      
      // Initialize the worker and get its routes
      try {
        await worker.getRoutes();
      } catch (routeError) {
        logger.log('warn', `Failed to get routes for worker ${workerName}: ${routeError.message}`);
        // Continue anyway since we found the worker
      }
      
      return worker;
    } catch (error) {
      logger.log('warn', `Worker '${workerName}' not found: ${error.message}`);
      return undefined;
    }
  }

  /**
   * Lists all worker scripts
   * @returns Array of worker scripts
   */
  public async listWorkerScripts() {
    if (!this.cfAccount.preselectedAccountId) {
      throw new Error('No account selected. Please select it first on the account.');
    }
    
    try {
      // Collect all scripts using the new client's async iterator
      const workerScripts: plugins.ICloudflareTypes['Script'][] = [];
      
      try {
        for await (const script of this.cfAccount.apiAccount.workers.scripts.list({
          account_id: this.cfAccount.preselectedAccountId,
        })) {
          workerScripts.push(script);
        }
        
        logger.log('info', `Found ${workerScripts.length} worker scripts`);
        return workerScripts;
      } catch (error) {
        logger.log('warn', `Error while listing workers with async iterator: ${error.message}`);
        
        // Try alternative approach if the async iterator fails
        const result = await this.cfAccount.apiAccount.workers.scripts.list({
          account_id: this.cfAccount.preselectedAccountId,
        }) as any;
        
        // Check if the result has a 'result' property (older API response format)
        if (result && result.result && Array.isArray(result.result)) {
          logger.log('info', `Found ${result.result.length} worker scripts using direct result`);
          return result.result;
        }
      }
      
      logger.log('warn', 'Could not retrieve worker scripts');
      return [];
    } catch (error) {
      logger.log('error', `Failed to list worker scripts: ${error.message}`);
      return [];
    }
  }
  
  /**
   * Deletes a worker script
   * @param workerName Name of the worker to delete
   * @returns True if deletion was successful
   */
  public async deleteWorker(workerName: string): Promise<boolean> {
    if (!this.cfAccount.preselectedAccountId) {
      throw new Error('No account selected. Please select it first on the account.');
    }
    
    try {
      await this.cfAccount.apiAccount.workers.scripts.delete(workerName, {
        account_id: this.cfAccount.preselectedAccountId
      });
      logger.log('info', `Worker '${workerName}' deleted successfully`);
      return true;
    } catch (error) {
      logger.log('error', `Failed to delete worker '${workerName}': ${error.message}`);
      return false;
    }
  }
}