import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
import { In } from 'typeorm'

import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'

import { NotificationRule } from './notification-rule'
import { NewNotificationRule, NotificationRulePatch } from './notification-rule-type'

@Resolver(NotificationRule)
export class NotificationRuleMutation {
  @Directive('@transaction')
  @Mutation(returns => NotificationRule, { description: 'To create new NotificationRule' })
  async createNotificationRule(
    @Arg('notificationRule') notificationRule: NewNotificationRule,
    @Ctx() context: ResolverContext
  ): Promise<NotificationRule> {
    const { domain, user, tx } = context.state

    const result = await tx.getRepository(NotificationRule).save({
      ...notificationRule,
      domain,
      creator: user,
      updater: user
    })

    if (notificationRule.thumbnail) {
      await createAttachment(
        null,
        {
          attachment: {
            file: notificationRule.thumbnail,
            refType: NotificationRule.name,
            refBy: result.id
          }
        },
        context
      )
    }

    return result
  }

  @Directive('@transaction')
  @Mutation(returns => NotificationRule, { description: 'To modify NotificationRule information' })
  async updateNotificationRule(
    @Arg('id') id: string,
    @Arg('patch') patch: NotificationRulePatch,
    @Ctx() context: ResolverContext
  ): Promise<NotificationRule> {
    const { domain, user, tx } = context.state

    const repository = tx.getRepository(NotificationRule)
    const notificationRule = await repository.findOne({
      where: { domain: { id: domain.id }, id }
    })

    const result = await repository.save({
      ...notificationRule,
      ...patch,
      updater: user
    })

    if (patch.thumbnail) {
      await deleteAttachmentsByRef(null, { refBys: [result.id] }, context)
      await createAttachment(
        null,
        {
          attachment: {
            file: patch.thumbnail,
            refType: NotificationRule.name,
            refBy: result.id
          }
        },
        context
      )
    }

    return result
  }

  @Directive('@transaction')
  @Mutation(returns => [NotificationRule], { description: "To modify multiple NotificationRules' information" })
  async updateMultipleNotificationRule(
    @Arg('patches', type => [NotificationRulePatch]) patches: NotificationRulePatch[],
    @Ctx() context: ResolverContext
  ): Promise<NotificationRule[]> {
    const { domain, user, tx } = context.state

    let results = []
    const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
    const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
    const notificationRuleRepo = tx.getRepository(NotificationRule)

    if (_createRecords.length > 0) {
      for (let i = 0; i < _createRecords.length; i++) {
        const newRecord = _createRecords[i]

        const result = await notificationRuleRepo.save({
          ...newRecord,
          domain,
          creator: user,
          updater: user
        })

        if (newRecord.thumbnail) {
          await createAttachment(
            null,
            {
              attachment: {
                file: newRecord.thumbnail,
                refType: NotificationRule.name,
                refBy: result.id
              }
            },
            context
          )
        }

        results.push({ ...result, cuFlag: '+' })
      }
    }

    if (_updateRecords.length > 0) {
      for (let i = 0; i < _updateRecords.length; i++) {
        const updateRecord = _updateRecords[i]
        const notificationRule = await notificationRuleRepo.findOneBy({ id: updateRecord.id })

        const result = await notificationRuleRepo.save({
          ...notificationRule,
          ...updateRecord,
          updater: user
        })

        if (updateRecord.thumbnail) {
          await deleteAttachmentsByRef(null, { refBys: [result.id] }, context)
          await createAttachment(
            null,
            {
              attachment: {
                file: updateRecord.thumbnail,
                refType: NotificationRule.name,
                refBy: result.id
              }
            },
            context
          )
        }

        results.push({ ...result, cuFlag: 'M' })
      }
    }

    return results
  }

  @Directive('@transaction')
  @Mutation(returns => Boolean, { description: 'To delete NotificationRule' })
  async deleteNotificationRule(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
    const { domain, tx } = context.state

    await tx.getRepository(NotificationRule).delete({ domain: { id: domain.id }, id })
    await deleteAttachmentsByRef(null, { refBys: [id] }, context)

    return true
  }

  @Directive('@transaction')
  @Mutation(returns => Boolean, { description: 'To delete multiple NotificationRules' })
  async deleteNotificationRules(
    @Arg('ids', type => [String]) ids: string[],
    @Ctx() context: ResolverContext
  ): Promise<boolean> {
    const { domain, tx } = context.state

    await tx.getRepository(NotificationRule).delete({
      domain: { id: domain.id },
      id: In(ids)
    })

    await deleteAttachmentsByRef(null, { refBys: ids }, context)

    return true
  }

  @Directive('@transaction')
  @Mutation(returns => Boolean, { description: 'To import multiple NotificationRules' })
  async importNotificationRules(
    @Arg('notificationRules', type => [NotificationRulePatch]) notificationRules: NotificationRulePatch[],
    @Ctx() context: ResolverContext
  ): Promise<boolean> {
    const { domain, tx } = context.state

    await Promise.all(
      notificationRules.map(async (notificationRule: NotificationRulePatch) => {
        const createdNotificationRule: NotificationRule = await tx
          .getRepository(NotificationRule)
          .save({ domain, ...notificationRule })
      })
    )

    return true
  }
}
