"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateDispatcher = generateDispatcher;
const generator_1 = require("@postxl/generator");
function generateDispatcher({ actions, database, types }) {
    const imports = generator_1.ImportGenerator.from(actions.dispatcher.location);
    imports.add(database.service);
    imports.add(actions.execution.class);
    imports.add(actions.execution.interface);
    imports.add(actions.summary.action);
    imports.add(actions.summary.result);
    imports.add(actions.summary.resultOfActionHelper);
    imports.add(actions.authorization.service);
    imports.addType(types.user);
    const injections = [];
    const executeMethods = [];
    if (actions.providers.length === 0) {
        executeMethods.push(`case 'NoOp': 
      throw new Error('This is only added to ensure it compiles. To be deleted once more actions are added!')
    `);
    }
    for (const { service, scopes } of actions.providers) {
        imports.add(service);
        injections.push(`@Inject(forwardRef(() => ${service.name})) private readonly ${service.variableName}: ${service.name}`);
        for (const scopeName of scopes) {
            executeMethods.push(`
        case '${scopeName}': 
          return this.${service.variableName}.dispatch({ action, execution }) as Promise<Result>`);
        }
    }
    return /* ts */ `
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common'

import { ExhaustiveSwitchCheck } from '@postxl/utils'
${imports.generate()}



@Injectable()
export class DispatcherService {
  private readonly logger = new Logger(DispatcherService.name)

  constructor(
    private readonly databaseService: DatabaseService,
    private readonly actionExecutionFactory: ActionExecutionFactory,
    private readonly authorizationService: AuthorizationService,
    ${injections.join(',\n    ')}
  ) {}

  public async dispatch<
    A extends Action,
    Result = ${actions.summary.resultOfActionHelper.name}<A, ${actions.summary.result.name}>
  >({ action, user, migrationOrder }: { action: A; user: User; migrationOrder?: number }): Promise<Result> {
    const execution = await this.actionExecutionFactory.create({ action, databaseService: this.databaseService, user, migrationOrder })

    const isAuthorized = await this.authorizationService.authorizeAction({ action, user, execution })
    if (!isAuthorized) {
      const message = \`User \${user.id} is not authorized to execute \${action.scope}.\${action.type}\`
      await execution.error(message)
      this.logger.warn(message)
      throw new Error(message)
    }

    try {
      const result = await this.execute({ action, execution })

      await execution.success(result)

      return result
    } catch (e) {
      await execution.error(e)
      throw e
    }
  }

  private async execute<
    A extends Action,
    Result = ${actions.summary.resultOfActionHelper.name}<A, ${actions.summary.result.name}>
  >({
    action,
    execution,
  }: {
    action: A
    execution: IActionExecution
  }): Promise<Result> {
    // prettier-ignore
    switch (action.scope) { // NOSONAR - this must cover all cases
      ${executeMethods.join('\n')}
      
      default:
        throw new ExhaustiveSwitchCheck(action)
    }
  }
}
`;
}
//# sourceMappingURL=dispatcher-service.generator.js.map