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

import { getRedirectSubdomainPath } from '@things-factory/shell'
import { DesignPackage } from './design-package'
import { Process } from '../process/process'
import { NewDesignPackage, DesignPackagePatch } from './design-package-type'
import { thumbnail } from '../../controllers/thumbnail'

@Resolver(DesignPackage)
export class DesignPackageMutation {
  @Directive('@transaction')
  @Directive('@privilege(category: "design-package", privilege: "mutation", domainOwnerGranted: true)')
  @Mutation(returns => DesignPackage, { description: 'To create new DesignPackage' })
  async createDesignPackage(
    @Arg('designPackage') designPackage: NewDesignPackage,
    @Ctx() context: ResolverContext
  ): Promise<DesignPackage> {
    const { domain, user, tx } = context.state
    const repository = tx.getRepository(DesignPackage)

    const oldDesignPackage: DesignPackage = await repository.findOneBy({
      name: designPackage.name,
      domain: { id: domain.id }
    })

    if (oldDesignPackage) {
      throw new Error(context.t('error.design-package name is already taken', { name: designPackage.name }))
    }

    const newDesignPackage: Partial<DesignPackage> = {
      ...designPackage
    }

    const base64 = await thumbnail({
      model: designPackage.model,
      context
    })

    if (base64) {
      newDesignPackage.thumbnail = 'data:image/png;base64,' + base64.toString('base64')
    } else {
      newDesignPackage.thumbnail = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
    }

    return await repository.save({
      domain,
      ...newDesignPackage,
      creator: user,
      updater: user
    })
  }

  @Directive('@transaction')
  @Directive('@privilege(category: "design-package", privilege: "mutation", domainOwnerGranted: true)')
  @Mutation(returns => DesignPackage, { description: 'To modify DesignPackage information' })
  async updateDesignPackage(
    @Arg('id') id: string,
    @Arg('patch') patch: DesignPackagePatch,
    @Ctx() context: ResolverContext
  ): Promise<DesignPackage> {
    const { domain, user, tx } = context.state
    const repository = tx.getRepository(DesignPackage)

    const designPackage = await repository.findOne({
      where: { domain: { id: domain.id }, id }
    })

    if (patch.model) {
      const base64 = await thumbnail({
        model: patch.model,
        context
      })

      if (base64) {
        patch.thumbnail = 'data:image/png;base64,' + base64.toString('base64')
      } else {
        patch.thumbnail = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
      }
    }

    return await repository.save({
      ...designPackage,
      ...patch,
      updater: user
    })
  }

  @Directive('@transaction')
  @Directive('@privilege(category: "design-package", privilege: "mutation", domainOwnerGranted: true)')
  @Mutation(returns => Boolean, { description: 'To delete DesignPackage' })
  async deleteDesignPackage(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
    const { domain, tx } = context.state

    await tx.getRepository(DesignPackage).delete({ domain: { id: domain.id }, id })

    return true
  }

  @Directive('@transaction')
  @Directive('@privilege(category: "design-package", privilege: "mutation", domainOwnerGranted: true)')
  @Mutation(returns => DesignPackage, { description: 'To register a process as a process template with the given ID' })
  async registerProcessAsTemplate(
    @Arg('id', { description: 'process Id to be regiestered' }) id: string,
    @Arg('name', { description: 'name of process template to be regiestered' }) name: string,
    @Arg('description', { description: 'description of process template to be regiestered' }) description: string,
    @Arg('visibility', { description: 'visibility of process template to be regiestered' }) visibility: string,
    @Ctx() context: ResolverContext
  ): Promise<DesignPackage> {
    const { domain, user, notify, tx } = context.state

    const boardTemplateRepository = tx.getRepository(DesignPackage)

    const process = await tx.getRepository(Process).findOne({
      where: { domain: { id: domain.id }, id }
    })

    if (!process) {
      throw `Process given id(${id}) is not found`
    }

    name ||= process.name

    const { model, thumbnail } = process

    const designPackage = await boardTemplateRepository.findOne({
      where: { domain: { id: domain.id }, name }
    })

    const registered = designPackage
      ? await boardTemplateRepository.save({
          ...designPackage,
          name,
          description: description || designPackage.description,
          visibility: visibility || designPackage.visibility,
          model,
          thumbnail,
          updater: user
        })
      : await boardTemplateRepository.save({
          domain: { id: domain.id },
          name,
          description: description || process.description,
          model,
          thumbnail,
          visibility: visibility || 'private',
          updater: user,
          creator: user
        })

    notify &&
      notify({
        mode: 'in-app',
        title: `DesignPackage '${registered.name}' registered`,
        body: `DesignPackage '${registered.name}' registered by ${user.name}\n${registered.description}`,
        image: getRedirectSubdomainPath(context, domain.subdomain, `/design-package-thumbnail/${registered.id}`),
        url: getRedirectSubdomainPath(context, domain.subdomain, `/design-package-viewer/${registered.id}`)
      })

    return registered
  }
}
