import * as plugins from '../plugins.js';
import * as paths from '../paths.js';
import { SzDcRouterConnector } from './classes.dcr.sz.connector.js';

import type { SzPlatformService } from '../platformservice.js';
import { type IMtaConfig, MtaService } from '../mta/classes.mta.js';

// Types are referenced via plugins.smartproxy.*

export interface IDcRouterOptions {
  platformServiceInstance?: SzPlatformService;

  /** SmartProxy (TCP/SNI) configuration */
  smartProxyOptions?: plugins.smartproxy.ISmartProxyOptions;
  /** Reverse proxy host configurations for HTTP(S) layer */
  reverseProxyConfigs?: plugins.smartproxy.IReverseProxyConfig[];
  /** MTA (SMTP) service configuration */
  mtaConfig?: IMtaConfig;
  /** DNS server configuration */
  dnsServerConfig?: plugins.smartdns.IDnsServerOptions;
}

/**
 * DcRouter can be run on ingress and egress to and from a datacenter site.
 */
/**
 * Context passed to HTTP routing rules
 */
/**
 * Context passed to port proxy (SmartProxy) routing rules
 */
export interface PortProxyRuleContext {
  proxy: plugins.smartproxy.SmartProxy;
  configs: plugins.smartproxy.IPortProxySettings['domainConfigs'];
}
export class DcRouter {
  public szDcRouterConnector = new SzDcRouterConnector(this);
  public options: IDcRouterOptions;
  public smartProxy?: plugins.smartproxy.SmartProxy;
  public mta?: MtaService;
  public dnsServer?: plugins.smartdns.DnsServer;
  /** SMTP rule engine */
  public smtpRuleEngine?: plugins.smartrule.SmartRule<any>;
  constructor(optionsArg: IDcRouterOptions) {
    this.options = optionsArg;
  }

  public async start() {

    // TCP/SNI proxy (SmartProxy)
    if (this.options.smartProxyOptions) {
      // Lets setup smartacme
      let certProvisionFunction: plugins.smartproxy.ISmartProxyOptions['certProvisionFunction'];
      if (true) {
        const smartAcmeInstance = new plugins.smartacme.SmartAcme({
          accountEmail: this.options.smartProxyOptions.acme.accountEmail,
          certManager: new plugins.smartacme.certmanagers.MongoCertManager({
            mongoDbUrl: await this.szDcRouterConnector.getEnvVarOnDemand('MONGO_DB_URL'),
            mongoDbUser: await this.szDcRouterConnector.getEnvVarOnDemand('MONGO_DB_USER'),
            mongoDbPass: await this.szDcRouterConnector.getEnvVarOnDemand('MONGO_DB_PASS'),
            mongoDbName: await this.szDcRouterConnector.getEnvVarOnDemand('MONGO_DB_NAME'),
          }),
          environment: 'production',
          accountPrivateKey: await this.szDcRouterConnector.getEnvVarOnDemand('ACME_ACCOUNT_PRIVATE_KEY'),
          challengeHandlers: [
            new plugins.smartacme.handlers.Dns01Handler(new plugins.cloudflare.CloudflareAccount('')) // TODO
          ],

        });
        certProvisionFunction = async (domainArg) => {
          const domainSupported = await smartAcmeInstance.challengeHandlers[0].checkWetherDomainIsSupported(domainArg);
          if (!domainSupported) {
            return 'http01';
          }
          return smartAcmeInstance.getCertificateForDomain(domainArg);
        };
      }

      this.smartProxy = new plugins.smartproxy.SmartProxy(this.options.smartProxyOptions);
      // Initialize SMTP rule engine from MTA service if available
      if (this.mta) {
        this.smtpRuleEngine = this.mta.smtpRuleEngine;
      }
    }
    // MTA service
    if (this.options.mtaConfig) {
      this.mta = new MtaService(null, this.options.mtaConfig);
    }
    // DNS server
    if (this.options.dnsServerConfig) {
      this.dnsServer = new plugins.smartdns.DnsServer(this.options.dnsServerConfig);
    }



    // Start SmartProxy if configured
    if (this.smartProxy) {
      await this.smartProxy.start();
    }
    // Start MTA service if configured
    if (this.mta) {
      await this.mta.start();
    }
    // Start DNS server if configured
    if (this.dnsServer) {
      await this.dnsServer.start();
    }
  }

  public async stop() {
    // Stop SmartProxy
    if (this.smartProxy) {
      await this.smartProxy.stop();
    }
    // Stop MTA service
    if (this.mta) {
      await this.mta.stop();
    }
    // Stop DNS server
    if (this.dnsServer) {
      await this.dnsServer.stop();
    }
  }

  /**
   * Register an SMTP routing rule
   */
  public addSmtpRule(
    priority: number,
    check: (email: any) => Promise<any>,
    action: (email: any) => Promise<any>
  ): void {
    this.smtpRuleEngine?.createRule(priority, check, action);
  }
}

export default DcRouter;