import * as plugins from './plugins.js';
import { CloudlyConfig } from './classes.config.js';

// interfaces
import {} from '@tsclass/tsclass';

// Cloudly mods
import { CloudlyInfo } from './classes.cloudlyinfo.js';
import { CloudlyServer } from './classes.server.js';

// connectors
import { CloudflareConnector } from './connector.cloudflare/connector.js';
import { LetsencryptConnector } from './connector.letsencrypt/connector.js';
import { MongodbConnector } from './connector.mongodb/connector.js';

// processes
import { CloudlyCoreflowManager } from './manager.coreflow/coreflowmanager.js';
import { ClusterManager } from './manager.cluster/classes.clustermanager.js';
import { CloudlyTaskmanager } from './manager.task/taskmanager.js';
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js';
import { CloudlyServerManager } from './manager.server/classes.servermanager.js';
import { ExternalApiManager } from './manager.status/statusmanager.js';
import { ExternalRegistryManager } from './manager.externalregistry/index.js';
import { ImageManager } from './manager.image/classes.imagemanager.js';
import { logger } from './logger.js';
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';

/**
 * Cloudly class can be used to instantiate a cloudly server.
 * It is implemented as class in order to make it easier ro write node services that are more adjusted to invidual services
 *
 * ```ts
 * const mycloudly = new Cloudly ({...})
 * ```
 */
export class Cloudly {
  public typedrouter = new plugins.typedrequest.TypedRouter();

  public config: CloudlyConfig;
  public logger: plugins.smartlog.Smartlog;
  public ready: Promise<any>;

  // mods
  public cloudlyInfo: CloudlyInfo;
  public server: CloudlyServer;

  // connectors
  public cloudflareConnector: CloudflareConnector;
  public letsencryptConnector: LetsencryptConnector;
  public mongodbConnector: MongodbConnector;

  // managers
  public authManager: CloudlyAuthManager;
  public secretManager: CloudlySecretManager;
  public clusterManager: ClusterManager;
  public coreflowManager: CloudlyCoreflowManager;
  public externalApiManager: ExternalApiManager;
  public externalRegistryManager: ExternalRegistryManager;
  public imageManager: ImageManager;
  public taskManager: CloudlyTaskmanager;
  public serverManager: CloudlyServerManager;

  private readyDeferred = new plugins.smartpromise.Deferred();

  private configOptions: plugins.servezoneInterfaces.data.ICloudlyConfig;
  constructor(configArg?: plugins.servezoneInterfaces.data.ICloudlyConfig) {
    this.configOptions = configArg;
    this.cloudlyInfo = new CloudlyInfo(this);
    this.config = new CloudlyConfig(this);

    this.logger = logger;
    this.server = new CloudlyServer(this);
    this.ready = this.readyDeferred.promise;

    // connectors
    this.mongodbConnector = new MongodbConnector(this); // database needs to go first
    this.cloudflareConnector = new CloudflareConnector(this);
    this.letsencryptConnector = new LetsencryptConnector(this);

    // managers
    this.authManager = new CloudlyAuthManager(this);
    this.clusterManager = new ClusterManager(this);
    this.coreflowManager = new CloudlyCoreflowManager(this);
    this.externalApiManager = new ExternalApiManager(this);
    this.externalRegistryManager = new ExternalRegistryManager(this);
    this.imageManager = new ImageManager(this);
    this.taskManager = new CloudlyTaskmanager(this);
    this.secretManager = new CloudlySecretManager(this);
    this.serverManager = new CloudlyServerManager(this);
  }

  /**
   * starts the cloudly instance and
   * @param configArg
   */
  public async start() {
    // config
    await this.config.init(this.configOptions);

    // manageers
    await this.authManager.start();
    await this.secretManager.start();
    await this.serverManager.start();

    // connectors
    await this.mongodbConnector.init();
    await this.cloudflareConnector.init();
    await this.letsencryptConnector.init();
    await this.clusterManager.init();
    await this.server.start();
    this.readyDeferred.resolve();

    // start the managers
    this.imageManager.start();
  }

  /**
   * stop the reception instance
   */
  public async stop() {
    await this.server.stop();
    await this.letsencryptConnector.stop();
    await this.mongodbConnector.stop();
    await this.secretManager.stop();
  }
}