import * as plugins from '../../plugins.ts';
import { logger } from '../../logging.ts';
import type { OpsServer } from '../classes.opsserver.ts';
import * as interfaces from '../../../ts_interfaces/index.ts';
import { requireAdminIdentity } from '../helpers/guards.ts';

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

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

  private registerHandlers(): void {
    // Get app templates (catalog)
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetAppTemplates>(
        'getAppTemplates',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const apps = await this.opsServerRef.oneboxRef.appStore.getApps();
          return { apps };
        },
      ),
    );

    // Get app config for a specific version
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetAppConfig>(
        'getAppConfig',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const config = await this.opsServerRef.oneboxRef.appStore.getAppVersionConfig(
            dataArg.appId,
            dataArg.version,
          );
          const appMeta = await this.opsServerRef.oneboxRef.appStore.getAppMeta(dataArg.appId);
          return { config, appMeta };
        },
      ),
    );

    // Get services with available upgrades
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetUpgradeableServices>(
        'getUpgradeableServices',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
          const services = await this.opsServerRef.oneboxRef.appStore.getUpgradeableServices();
          return { services };
        },
      ),
    );

    // Upgrade a service to a new template version
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpgradeService>(
        'upgradeService',
        async (dataArg) => {
          await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);

          const existingService = this.opsServerRef.oneboxRef.database.getServiceByName(dataArg.serviceName);
          if (!existingService) {
            throw new plugins.typedrequest.TypedResponseError(`Service not found: ${dataArg.serviceName}`);
          }
          if (!existingService.appTemplateId) {
            throw new plugins.typedrequest.TypedResponseError('Service was not deployed from an app template');
          }
          if (!existingService.appTemplateVersion) {
            throw new plugins.typedrequest.TypedResponseError('Service has no tracked template version');
          }

          logger.info(`Upgrading service '${dataArg.serviceName}' from v${existingService.appTemplateVersion} to v${dataArg.targetVersion}`);

          // Execute migration
          const migrationResult = await this.opsServerRef.oneboxRef.appStore.executeMigration(
            existingService,
            existingService.appTemplateVersion,
            dataArg.targetVersion,
          );

          if (!migrationResult.success) {
            throw new plugins.typedrequest.TypedResponseError(
              `Migration failed: ${migrationResult.warnings.join('; ')}`,
            );
          }

          // Apply the upgrade
          const updatedService = await this.opsServerRef.oneboxRef.appStore.applyUpgrade(
            dataArg.serviceName,
            migrationResult,
            dataArg.targetVersion,
          );

          return {
            service: updatedService,
            warnings: migrationResult.warnings,
          };
        },
      ),
    );
  }
}
