import express from 'express';
import cors from 'cors';
import type { Server } from 'http';
import type { Application, Request, Response } from 'express';

export type AskControllerLike = {
  handleAsk: (req: Request, res: Response) => Promise<Response> | Response;
  health: (req: Request, res: Response) => Response;
};

export type ApiServerDeps = {
  askController: AskControllerLike;
  app?: Application; // ✅ allow injecting existing express app
  mountPath?: string; // ✅ mount ask routes under a prefix (default "")
  enableCors?: boolean; // ✅ if your app already uses cors, you can disable here
};

export class ApiServer {
  private askController: AskControllerLike;
  public app: Application;
  private server: Server | null;
  private mountPath: string;

  constructor({
    askController,
    app,
    mountPath = '',
    enableCors = false,
  }: ApiServerDeps) {
    this.askController = askController;
    this.app = app ?? express();
    this.server = null;
    this.mountPath = mountPath;

    // If you're injecting your existing app that already has cors, keep enableCors=false
    this.app.disable('x-powered-by');
    if (enableCors) this.app.use(cors());

    this.registerRoutes();
  }

  private join = (base: string, p: string): string => {
    const b = (base || '').trim();
    if (!b || b === '/') return p.startsWith('/') ? p : `/${p}`;
    const baseClean = b.endsWith('/') ? b.slice(0, -1) : b;
    const pathClean = p.startsWith('/') ? p : `/${p}`;
    return `${baseClean}${pathClean}`;
  };

  private registerRoutes = (): void => {
    // ✅ avoids clobbering your existing "/" route
    this.app.get(
      this.join(this.mountPath, '/ask/deprecated'),
      this.askController.handleAsk,
    );
    this.app.get(
      this.join(this.mountPath, '/ask/health/deprecated'),
      this.askController.health,
    );
  };

  listen = (port: number, onListening?: () => void): Server => {
    this.server = this.app.listen(port, onListening);
    return this.server;
  };

  close = (): void => {
    if (!this.server) return;
    this.server.close(() => {});
    this.server = null;
  };
}
