import { spawn, ChildProcessWithoutNullStreams } from 'child_process';
import path from 'path';

export default class PythonSubprocessManager {
  // eslint-disable-next-line no-use-before-define
  public static instance: PythonSubprocessManager | null = null;

  private process: ChildProcessWithoutNullStreams | null = null;

  private scriptPath: string;

  private working_dir: string = path.join(
    __dirname,
    '..',
    '..',
    '..',
    'audio-service',
  );

  public portNumber: number | null = null;

  constructor(scriptPath: string) {
    this.scriptPath = scriptPath;
    PythonSubprocessManager.instance = this;
  }

  start(args: string[] = []): void {
    if (this.process) {
      throw new Error('Process already running.');
    }
    console.log(`Using Python working directory at: ${this.working_dir}`);
    console.log(`Starting Python subprocess with script: ${this.scriptPath}`);
    this.process = spawn(
      'venv/Scripts/python.exe',
      [this.scriptPath, ...args],
      {
        cwd: this.working_dir,
        detached: false,
        stdio: 'pipe',
      },
    );
    this.process.stdout.on('data', (data: Buffer) => {
      // console.log(`Python stdout: ${data.toString()}`);
    });
    this.process.stderr.on('data', (data: Buffer) => {
      // console.error(`Python stderr: ${data.toString()}`);
      const lines = data.toString().split('\n');
      // eslint-disable-next-line no-restricted-syntax
      for (const line of lines) {
        const match = line.match(/Running on .*:(\d+)/);
        if (match) {
          const port = parseInt(match[1], 10);
          console.log(`Detected port: ${port}`);
          this.portNumber = port;
        }
      }
    });
    this.process.on('exit', () => {
      console.log('Python subprocess exited.');
      this.process = null;
    });
  }

  stop(): void {
    if (this.process) {
      // for some reason, process.kill() doens't work well with flask. todo: investigate further
      // spawn('taskkill', ['/pid', `${this.process.pid}`, '/f', '/t']);
      this.process.kill();
      this.process = null;
    }
  }

  restart(args: string[] = []): void {
    this.stop();
    this.start(args);
  }

  isHealthy(): boolean {
    return !!this.process && !this.process.killed;
  }
}
