"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateSeedService = generateSeedService;
const Generator = __importStar(require("@postxl/generator"));
const schema_1 = require("@postxl/schema");
function generateSeedService(context) {
    const seedData = context.seedData;
    const userModel = context.models.get(schema_1.standardModelName_User);
    if (!userModel || userModel.repository.kind === 'NoRepository') {
        throw new Error(`User model is required for seed migrations and must have a repository!`);
    }
    const actionsModel = context.models.get(schema_1.standardModelName_Action);
    if (!actionsModel || actionsModel.repository.kind === 'NoRepository') {
        throw new Error(`Action model is required for seed migrations and must have a repository!`);
    }
    const imports = Generator.ImportGenerator.from(context.seed.service.location)
        .add(context.actions.dispatcher)
        .add(context.actions.summary.action)
        .add(context.import.actions.excel.action)
        .add(context.import.actions.excelSeed.action)
        .add(context.repositories.dataService)
        .addType(seedData.migrationTypes.summary)
        .addType(seedData.migrationTypes.excel)
        .addType(seedData.migrationTypes.excelSeed)
        .add(seedData.seedMigrations);
    return `
import { readFile } from 'node:fs/promises'

${imports.generate()}
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common'

import { ExhaustiveSwitchCheck, format } from '@postxl/utils'

@Injectable()
export class ${context.seed.service.name} {
  private readonly logger = new Logger(${context.seed.service.name}.name)

  constructor(
    private readonly data: ${context.repositories.dataService.name},
    @Inject(forwardRef(() => ${context.actions.dispatcher.name})) private readonly dispatcherService: ${context.actions.dispatcher.name},
  ) {}

  /**
   * To be called on application startup. Will validate the seed data migrations and execute any pending migrations.
   *
   * Each migration is an action, i.e. will be dispatched via the default dispatcher service and logged like any other action.
   */
  public async seed() {
    this.verifyIntegrity()

    // We initialize relevant repositories before seeding
    // but ignore errors
    await this.data.init(true)

    let executed = 0
    for (const migration of migrations) {
      // Skip any migrations that have already been executed
      const migrationExists = await this.data.actions.findFirst({
        predicate: (action) => action.migrationOrder === migration.order && action.status === 'Success',
        prisma: {migration_order: migration.order, status: 'Success'}
      })

      if (migrationExists) {
        continue
      }

      const action = await this.convertToAction(migration)

      this.logger.log(\`Executing seed migration \${migration.order} - \${migration.name}\`)
      await this.dispatcherService.dispatch({ action, user: this.data.users.rootUser, migrationOrder: migration.order })

      executed++
    }

    if (executed === 0) {
      if (migrations.length > 0) {
        this.logger.log(\`✅ All \${format(migrations.length)} seed migrations have already been applied\`)
      } else {
        this.logger.log('No seed migrations found.')
      }
    } else if (executed === migrations.length) {
      this.logger.log(\`✅ Executed all \${format(executed)} seed migrations\`)
    } else {
      this.logger.log(
        \`✅ Executed \${format(executed)} seed migrations, skipped \${format(migrations.length - executed)} previous migrations\`,
      )
    }
  }

  private async convertToAction(migration: ${seedData.migrationTypes.summary.name}): Promise<Action> {
    switch (migration.type) {
      case '${seedData.migrationTypes.customAction.discriminant}':
        return migration.action
      case '${seedData.migrationTypes.excel.discriminant}':
      case '${seedData.migrationTypes.excelSeed.discriminant}':
        return await this.convertExcelToAction(migration)

      default:
        throw new ExhaustiveSwitchCheck(migration)
    }
  }

  /**
   * Checks if the order of the migrations is correct and if there are any missing migrations.
   */
  private verifyIntegrity() {
    let startOrder = 0
    for (const { name, order } of migrations) {
      if (order <= startOrder) {
        throw new Error(
          \`Invalid migration order. The order of migration "\${name}" must be after \${startOrder} but is \${order}. Is the order field correct and the order in the migrations array correct?\`,
        )
      }
      startOrder = order
    }
  }

  /**
   * Reads the Excel file and passes it as the payload to the import action.
   */
  private async convertExcelToAction(
    migration: ${seedData.migrationTypes.excel.name} | ${seedData.migrationTypes.excelSeed.name},
  ): Promise<${context.import.actions.excel.action.name} | ${context.import.actions.excelSeed.action.name}> {
    const data = await this.readFileToBuffer(migration.filename)
    return {
      scope: 'import',
      type: migration.type,
      payload: { filename: migration.filename, data },
    }
  }

  private async readFileToBuffer(filePath: string): Promise<Buffer<ArrayBuffer>> {
    try {
      const data = await readFile(filePath)
      return data as Buffer<ArrayBuffer>
    } catch (error) {
      this.logger.error(\`Error reading file from disk: \${JSON.stringify(error)}\`)
      throw error
    }
  }
}`;
}
//# sourceMappingURL=seed-service.generator.js.map