import { TypedServer, type THealthCheckFunction } from '../classes.typedserver.js';

export interface ILoleServiceServerConstructorOptions {
  addCustomRoutes?: (typedserver: TypedServer) => Promise<any>;
  serviceName: string;
  serviceVersion: string;
  serviceDomain: string;
  port?: number;
}

// the main service server
export class UtilityServiceServer {
  public options: ILoleServiceServerConstructorOptions;
  public typedServer: TypedServer;

  // Health checks registered before start() are applied once the inner
  // TypedServer exists.
  private pendingHealthChecks = new Map<string, THealthCheckFunction>();

  constructor(optionsArg: ILoleServiceServerConstructorOptions) {
    this.options = optionsArg;
  }

  /**
   * Register a named health check served by the built-in health endpoint.
   * Can be called before or after start().
   */
  public registerHealthCheck(nameArg: string, checkArg: THealthCheckFunction): void {
    if (this.typedServer) {
      this.typedServer.registerHealthCheck(nameArg, checkArg);
      return;
    }
    this.pendingHealthChecks.set(nameArg, checkArg);
  }

  public async start() {
    console.log('starting lole-serviceserver...');
    this.typedServer = new TypedServer({
      cors: true,
      domain: this.options.serviceDomain,
      forceSsl: false,
      port: this.options.port || 3000,
      robots: true,
      defaultAnswer: async () => {
        const InfoHtml = (await import('../infohtml/index.js')).InfoHtml;
        return (
          await InfoHtml.fromSimpleText(
            `${this.options.serviceName} (version ${this.options.serviceVersion})`
          )
        ).htmlString;
      },
    });

    // Apply health checks registered before start()
    for (const [name, checkFunction] of this.pendingHealthChecks) {
      this.typedServer.registerHealthCheck(name, checkFunction);
    }
    this.pendingHealthChecks.clear();

    // Add any custom routes
    if (this.options.addCustomRoutes) {
      await this.options.addCustomRoutes(this.typedServer);
    }

    await this.typedServer.start();
  }

  public async stop() {
    await this.typedServer.stop();
  }
}
