import * as plugins from '../../plugins.js';
import type { OpsServer } from '../classes.opsserver.js';
import * as interfaces from '../../../ts_interfaces/index.js';
import { requireAdminIdentity } from '../helpers/guards.js';
import { toApiData, toApiDataArray } from '../helpers/serialization.js';

export class SchedulesHandler {
  public typedrouter = new plugins.typedrequest.TypedRouter();

  constructor(private opsServerRef: OpsServer) {
    this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
    this.registerHandlers();
  }

  private registerHandlers(): void {
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackupSchedules>(
        'getBackupSchedules',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const schedules = await this.opsServerRef.oneboxRef.backupScheduler.getAllSchedules();
          return { schedules: toApiDataArray(schedules) };
        },
      ),
    );

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateBackupSchedule>(
        'createBackupSchedule',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const schedule = await this.opsServerRef.oneboxRef.backupScheduler.createSchedule(
            dataArg.scheduleConfig,
          );
          return { schedule: toApiData(schedule) };
        },
      ),
    );

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetBackupSchedule>(
        'getBackupSchedule',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const schedule = await this.opsServerRef.oneboxRef.backupScheduler.getScheduleById(dataArg.scheduleId);
          if (!schedule) {
            throw new plugins.typedrequest.TypedResponseError('Schedule not found');
          }
          return { schedule: toApiData(schedule) };
        },
      ),
    );

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateBackupSchedule>(
        'updateBackupSchedule',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const schedule = await this.opsServerRef.oneboxRef.backupScheduler.updateSchedule(
            dataArg.scheduleId,
            dataArg.updates,
          );
          return { schedule: toApiData(schedule) };
        },
      ),
    );

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteBackupSchedule>(
        'deleteBackupSchedule',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          await this.opsServerRef.oneboxRef.backupScheduler.deleteSchedule(dataArg.scheduleId);
          return { ok: true };
        },
      ),
    );

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_TriggerBackupSchedule>(
        'triggerBackupSchedule',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          await this.opsServerRef.oneboxRef.backupScheduler.triggerBackup(dataArg.scheduleId);
          // triggerBackup is void; the backup is created async by the scheduler
          // Return the most recent backup for the schedule
          const allBackups = await this.opsServerRef.oneboxRef.backupManager.listBackups();
          const latestBackup = allBackups.find((b: any) => b.scheduleId === dataArg.scheduleId);
          return { backup: toApiData(latestBackup!) };
        },
      ),
    );
  }
}
