import * as plugins from './smartdaemon.plugins.js';
import * as paths from './smartdaemon.paths.js';
import { SmartDaemon } from './smartdaemon.classes.smartdaemon.js';
import {
  ISmartDaemonServiceConstructorOptions,
  SmartDaemonService,
} from './smartdaemon.classes.service.js';

export class SmartDaemonSystemdManager {
  // STATIC
  private static smartDaemonNamespace = 'smartdaemon';

  public static createServiceNameFromServiceName(serviceNameArg: string) {
    return `${SmartDaemonSystemdManager.smartDaemonNamespace}_${serviceNameArg}`;
  }

  public static createFileNameFromServiceName(serviceNameArg: string) {
    return `${SmartDaemonSystemdManager.createServiceNameFromServiceName(serviceNameArg)}.service`;
  }

  public static createFilePathFromServiceName(serviceNameArg: string) {
    return plugins.path.join(
      paths.systemdDir,
      SmartDaemonSystemdManager.createFileNameFromServiceName(serviceNameArg)
    );
  }

  // INSTANCE
  public smartdaemonRef: SmartDaemon;
  public smartshellInstance: plugins.smartshell.Smartshell;
  public smartsystem: plugins.smartsystem.Smartsystem;

  public shouldExecute: boolean = false;

  constructor(smartdaemonRefArg: SmartDaemon) {
    this.smartdaemonRef = smartdaemonRefArg;
    this.smartshellInstance = new plugins.smartshell.Smartshell({
      executor: 'bash',
    });
    this.smartsystem = new plugins.smartsystem.Smartsystem();
  }

  public async checkElegibility() {
    if (await this.smartsystem.env.isLinuxAsync()) {
      this.shouldExecute = true;
    } else {
      console.log('Smartdaemon can only be used on Linux systems! Refusing to set up a service.');
      this.shouldExecute = false;
    }
    return this.shouldExecute;
  }

  public async execute(commandArg: string) {
    if (await this.checkElegibility()) {
      await this.smartshellInstance.exec(commandArg);
    }
  }

  /**
   * gets all services that are already present
   */
  public async getServices() {
    const existingServices: SmartDaemonService[] = [];
    if (await this.checkElegibility()) {
      const smartfmInstance = new plugins.smartfm.Smartfm({
        fmType: 'yaml',
      });
      const availableServices = await plugins.smartfile.fs.fileTreeToObject(
        paths.systemdDir,
        'smartdaemon_*.service'
      );
      for (const serviceFile of availableServices) {
        const data = smartfmInstance.parseFromComments('# ', serviceFile.contentBuffer.toString())
          .data as ISmartDaemonServiceConstructorOptions;
        const service = await SmartDaemonService.createFromOptions(this.smartdaemonRef, data);
        service.alreadyExists = true;
        existingServices.push(service);
      }
    }
    return existingServices;
  }

  public async startService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await this.execute(
        `systemctl start ${SmartDaemonSystemdManager.createServiceNameFromServiceName(
          serviceArg.name
        )}`
      );
    }
  }
  public async stopService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await this.execute(
        `systemctl stop ${SmartDaemonSystemdManager.createServiceNameFromServiceName(
          serviceArg.name
        )}`
      );
    }
  }

  public async saveService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await plugins.smartfile.memory.toFs(
        this.smartdaemonRef.templateManager.generateUnitFileForService(serviceArg),
        SmartDaemonSystemdManager.createFilePathFromServiceName(serviceArg.name)
      );
    }
  }

  public async deleteService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await plugins.smartfile.fs.remove(
        SmartDaemonSystemdManager.createServiceNameFromServiceName(serviceArg.name)
      );
    }
  }

  public async enableService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await this.saveService(serviceArg);
      if (serviceArg.alreadyExists) {
        await this.execute(`systemctl daemon-reload`);
      }
      await this.execute(
        `systemctl enable ${SmartDaemonSystemdManager.createServiceNameFromServiceName(
          serviceArg.name
        )}`
      );
    }
  }
  public async disableService(serviceArg: SmartDaemonService) {
    if (await this.checkElegibility()) {
      await this.execute(
        `systemctl disable ${SmartDaemonSystemdManager.createServiceNameFromServiceName(
          serviceArg.name
        )}`
      );
    }
  }

  public async reload() {
    if (await this.checkElegibility()) {
      await this.execute(`systemctl daemon-reload`);
    }
  }
}