import type AsyncProcess from './asyncProcess';
import {Scheduler} from '../../types/lrap';
// import childSchedulerRegistry, {ChildSchedulerRegistry} from '../child/childSchedulerRegistry';
import AsyncProcessPool from './asyncProcessPool';
// import type ChildPool from '../child/childPool';
// import {Constructor} from '../../types/util';

/**
 * Process context
 */
class ProcessContext {

  private _context: AsyncProcessPool.Context;
  private _scheduler: Scheduler<AsyncProcess>;
  // private _childPools = new Map<ChildSchedulerRegistry.ChildSchedulerEntry, AsyncProcessPool<any, any>>();
  private _runChildren?: boolean;
  private _process: AsyncProcess;
  // private _childPoolConstructor: Constructor<ChildPool<any>>;

  /**
   * Constructs instance
   * @param poolContext context from pool
   * @param scheduler process scheduler
   * @param childPoolConstructor child pool constructor
   */
  constructor(
    poolContext: AsyncProcessPool.Context,
    scheduler: Scheduler<AsyncProcess>,
    // childPoolConstructor: Constructor<ChildPool<any>>
  ) {
    this._context = poolContext;
    this._scheduler = scheduler;
    // this._childPoolConstructor = childPoolConstructor;
    
    // this._subscribeChildScheduler = this._subscribeChildScheduler.bind(this);
    // this._unsubscribeChildScheduler = this._unsubscribeChildScheduler.bind(this);
    // childSchedulerRegistry.on('childSchedulerSubscribed', this._subscribeChildScheduler);
    // childSchedulerRegistry.on('childSchedulerUnsubscribed', this._unsubscribeChildScheduler);
  }

  /**
   * Returns process ID
   * @returns process ID
   */
  get processId(): string {
    return this._context.processId;
  }

  /**
   * Returns current process stage
   * @returns process stage
   */
  get stage(): ProcessContext.ProcessStage {
    return this._context.stage;
  }

  /**
   * Whether the process was scheduled to cancel by external command (cancel or restart)
   * @returns whether canceled
   */
  get canceled(): boolean {
    return !!this._context.canceled;
  }

  /**
   * Returns process IDs chain from root process
   * @returns process IDs chain
   */
  getProcessIdChain(): string[] {
    return [this._context.processId];
  }

  /**
   * Process this context relates to. Called automatically by async pool
   * @param process current process
   */
  initialize(process: AsyncProcess) {
    this._process = process;
  }

  /**
   * Releases internal resources. Called automatically by async pool
   */
  release() {
    // childSchedulerRegistry.off('childSchedulerSubscribed', this._subscribeChildScheduler);
    // childSchedulerRegistry.off('childSchedulerUnsubscribed', this._unsubscribeChildScheduler);
  }

  /**
   * Starts running child processes
   */
  // startChildProcesses() {
  //   this._runChildren = true;
  //   for (let scheduler of childSchedulerRegistry.getChildSchedulers(this._scheduler)) {
  //     this._subscribeChildScheduler(this._scheduler, scheduler);
  //   }
  // }

  /**
   * Stops running child processes
   * @returns promise when all child processes fully stopped
   * @remarks parent process should await this method to ensure state consistency between parent and child processes
   */
  // async stopChildProcesses(): Promise<void> {
  //   delete this._runChildren;
  //   await Promise.all([...this._childPools.keys()].map(scheduler => {
  //     return this._unsubscribeChildScheduler(this._scheduler, scheduler);
  //   }));
  // }

  // private _subscribeChildScheduler(parent: Scheduler, entry: ChildSchedulerRegistry.ChildSchedulerEntry) {
  //   if (!this._runChildren || parent !== this._scheduler) {
  //     return;
  //   }
  //   let childPool = new this._childPoolConstructor(entry.childConstructor, {
  //     ...entry.options?.childPool,
  //     dependencies: entry.scheduler.dependencies,
  //     label: [
  //       this.getProcessIdChain().join(':'),
  //       entry.options?.childPool?.label || entry.scheduler.label || 'default'
  //     ].join(':')
  //   });
  //   this._childPools.set(entry, childPool);
  //   entry.scheduler.subscribePool(this.getProcessIdChain(), this._process, childPool);
  // }

  // private _unsubscribeChildScheduler(parent: Scheduler, entry: ChildSchedulerRegistry.ChildSchedulerEntry) {
  //   if (parent !== this._scheduler) {
  //     return;
  //   }
  //   if (this._childPools.has(entry)) {
  //     entry.scheduler.unsubscribePool(this.getProcessIdChain());
  //     let result = this._childPools.get(entry).stop();
  //     this._childPools.delete(entry);
  //     return result;
  //   }
  // }
}

namespace ProcessContext {

  /** Process stage */
  export enum ProcessStage {STARTING, RUNNING, STOPPING, STOPPED}
}

export default ProcessContext;
