import { FilterArgs, GraphQLServiceOptions, RoleEnum, Roles, ServiceOptions } from '<%= props.frameworkImport %>';
import { Inject } from '@nestjs/common';
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';

import { <%= props.namePascal %>Input } from './inputs/<%= props.nameKebab %>.input';
import { <%= props.namePascal %>CreateInput } from './inputs/<%= props.nameKebab %>-create.input';
import { FindAndCount<%= props.namePascal %>sResult } from './outputs/find-and-count-<%= props.nameKebab %>s-result.output';
import { <%= props.namePascal %> } from './<%= props.nameKebab %>.model';
import { <%= props.namePascal %>Service } from './<%= props.nameKebab %>.service';

/**
 * Resolver to process with <%= props.namePascal %> data
 */
@Roles(RoleEnum.ADMIN)
@Resolver(() => <%= props.namePascal %>)
export class <%= props.namePascal %>Resolver {

  /**
   * Import services
   */
  constructor(
    private readonly <%= props.nameCamel %>Service: <%= props.namePascal %>Service,
    @Inject('PUB_SUB') protected readonly pubSub: PubSub,
  ) {}

  // ===========================================================================
  // Queries
  // ===========================================================================

  /**
   * Get and total count <%= props.namePascal %>s (via filter)
   */
  @Roles(RoleEnum.S_USER)
  @Query(() => FindAndCount<%= props.namePascal %>sResult, { description: 'Find <%= props.namePascal %>s (via filter)' })
  async findAndCount<%= props.namePascal %>s(
    @GraphQLServiceOptions({ gqlPath: 'findAndCount<%= props.namePascal %>s.items' }) serviceOptions: ServiceOptions,
    @Args() args?: FilterArgs,
  ) {
    return await this.<%= props.nameCamel %>Service.findAndCount(args, {
      ...serviceOptions,
      inputType: FilterArgs,
    });
  }

  /**
   * Get <%= props.namePascal %>s (via filter)
   */
   @Roles(RoleEnum.S_USER)
   @Query(() => [<%= props.namePascal %>], { description: 'Find <%= props.namePascal %>s (via filter)' })
   async find<%= props.namePascal %>s(
     @GraphQLServiceOptions() serviceOptions: ServiceOptions,
     @Args() args?: FilterArgs,
   ) {
     return await this.<%= props.nameCamel %>Service.find(args, {
       ...serviceOptions,
       inputType: FilterArgs,
     });
   }

  /**
   * Get <%= props.namePascal %> via ID
   */
  @Roles(RoleEnum.S_USER)
  @Query(() => <%= props.namePascal %>, { description: 'Get <%= props.namePascal %> with specified ID' })
  async get<%= props.namePascal %>(
    @GraphQLServiceOptions() serviceOptions: ServiceOptions,
    @Args('id') id: string,
  ): Promise<<%= props.namePascal %>> {
    return await this.<%= props.nameCamel %>Service.get(id, serviceOptions);
  }

  // ===========================================================================
  // Mutations
  // ===========================================================================

  /**
   * Create new <%= props.namePascal %>
   */
  @Roles(RoleEnum.S_USER)
  @Mutation(() => <%= props.namePascal %>, { description: 'Create a new <%= props.namePascal %>' })
  async create<%= props.namePascal %>(
    @GraphQLServiceOptions() serviceOptions: ServiceOptions,
    @Args('input') input: <%= props.namePascal %>CreateInput,
  ): Promise<<%= props.namePascal %>> {
    return await this.<%= props.nameCamel %>Service.create(input, {
      ...serviceOptions,
      inputType: <%= props.namePascal %>CreateInput,
    });
  }

  /**
   * Delete existing <%= props.namePascal %>
   */
  @Roles(RoleEnum.S_USER)
  @Mutation(() => <%= props.namePascal %>, { description: 'Delete existing <%= props.namePascal %>' })
  async delete<%= props.namePascal %>(
    @GraphQLServiceOptions() serviceOptions: ServiceOptions,
    @Args('id') id: string,
  ): Promise<<%= props.namePascal %>> {
    return await this.<%= props.nameCamel %>Service.delete(id, {
      ...serviceOptions,
      roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR],
    });
  }

  /**
   * Update existing <%= props.namePascal %>
   */
  @Roles(RoleEnum.S_USER)
  @Mutation(() => <%= props.namePascal %>, { description: 'Update existing <%= props.namePascal %>' })
  async update<%= props.namePascal %>(
    @GraphQLServiceOptions() serviceOptions: ServiceOptions,
    @Args('id') id: string,
    @Args('input') input: <%= props.namePascal %>Input,
  ): Promise<<%= props.namePascal %>> {
    return await this.<%= props.nameCamel %>Service.update(id, input, {
      ...serviceOptions,
      inputType: <%= props.namePascal %>Input,
      roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR],
    });
  }

  // ===========================================================================
  // Subscriptions
  // ===========================================================================

  /**
   * Subscription for create <%= props.namePascal %>
   */
  @Subscription(() => <%= props.namePascal %>, {
    filter(this: <%= props.namePascal %>Resolver, payload, variables, context) {
      return context?.user?.hasRole?.(RoleEnum.ADMIN);
    },
    resolve: (value) => value,
  })
  async <%= props.nameCamel %>Created() {
    return this.pubSub.asyncIterableIterator('<%= props.nameCamel %>Created');
  }
}
