import { ConfigService, CrudService, ServiceOptions, assignPlain } from '<%= props.frameworkImport %>';
import { Inject, Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
<% if (props.isGql) { %>import { PubSub } from 'graphql-subscriptions';
<% } %>import { Model } from 'mongoose';

import { <%= props.namePascal %>Input } from './inputs/<%= props.nameKebab %>.input';
import { <%= props.namePascal %>CreateInput } from './inputs/<%= props.nameKebab %>-create.input';
import { <%= props.namePascal %>, <%= props.namePascal %>Document } from './<%= props.nameKebab %>.model';


/**
 * <%= props.namePascal %> service
 */
@Injectable()
export class <%= props.namePascal %>Service extends CrudService<<%= props.namePascal %>, <%= props.namePascal %>CreateInput, <%= props.namePascal %>Input> {

  // ===================================================================================================================
  // Properties
  // ===================================================================================================================

  // ===================================================================================================================
  // Injections
  // ===================================================================================================================

  /**
   * Constructor for injecting services
   *
   * Hints:
   * To resolve circular dependencies, integrate services as follows:
   * @Inject(forwardRef(() => XxxService)) protected readonly xxxService: WrapperType<XxxService>
   */
  constructor(
    protected override readonly configService: ConfigService,
    @InjectModel('<%= props.namePascal %>') protected readonly <%= props.nameCamel %>Model: Model<<%= props.namePascal %>Document>,
<% if (props.isGql) { %>    @Inject('PUB_SUB') protected readonly pubSub: PubSub,
<% } %>  ) {
    super({ configService, mainDbModel: <%= props.nameCamel %>Model, mainModelConstructor: <%= props.namePascal %> });
  }

  // ===================================================================================================================
  // Methods
  // ===================================================================================================================

  /**
   * Create new <%= props.namePascal %>
   * Overwrites create method from CrudService
   */
  override async create(input: <%= props.namePascal %>CreateInput, serviceOptions?: ServiceOptions): Promise<<%= props.namePascal %>> {
    // Get new <%= props.namePascal %>
    const created<%= props.namePascal %> = await super.create(input, serviceOptions);
<% if (props.isGql) { %>
    // Inform subscriber
    if (serviceOptions?.pubSub === undefined || serviceOptions.pubSub) {
      await this.pubSub.publish('<%= props.nameCamel %>Created', <%= props.namePascal %>.map(created<%= props.namePascal %>));
    }
<% } %>
    // Return created <%= props.namePascal %>
    return created<%= props.namePascal %>;
  }

  /**
   * Example method
   * Extends the CrudService
   */
  async exampleMethod(id: string, input: Record<string, any>, serviceOptions?: ServiceOptions): Promise<<%= props.namePascal %>> {

    // Get and check <%= props.namePascal %>
    const <%= props.nameCamel %> = await this.mainDbModel.findById(id).exec();
    if (!<%= props.nameCamel %>) {
      throw new NotFoundException(`<%= props.namePascal %> not found with ID: ${id}`);
    }

    // Process input and output
    return await this.process(async (data) => {

      // Update, save and return <%= props.namePascal %>
      return await assignPlain(<%= props.nameCamel %>, data.input).save();

    }, { input, serviceOptions });
  }
}
