import { Arg, Ctx, Mutation, Resolver, Directive } from 'type-graphql'
import { getRedirectSubdomainPath, getRepository } from '@things-factory/shell'

import { thumbnail } from '../../controllers/thumbnail'
import { ProcessGroup } from '../process-group/process-group'
import { Process } from './process'
import { ProcessPatch, NewProcess } from './process-type'

@Resolver(Process)
export class ProcessMutation {
  @Directive('@transaction')
  @Mutation(returns => Process, { description: 'To create new Process' })
  async createProcess(@Arg('process') process: NewProcess, @Ctx() context: ResolverContext): Promise<Process> {
    const { domain, user, notify, tx } = context.state
    const repository = tx.getRepository(Process)
    const groupRepository = tx.getRepository(ProcessGroup)

    const oldProcess: Process = await repository.findOneBy({
      name: process.name,
      domain: { id: domain.id },
      creator: { id: user.id }
    })

    if (oldProcess) {
      throw new Error(context.t('error.process name is already taken', { name: process.name }))
    }

    const newProcess: Process = {
      ...process
    }

    if (process.groupId) {
      newProcess.group = await groupRepository.findOneBy({
        id: process.groupId
      })
    }

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

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

    const created = await repository.save({
      domain,
      ...newProcess,
      creator: user,
      updater: user
    })

    notify &&
      notify({
        mode: 'in-app',
        title: `Process '${created.name}' created`,
        body: `Process '${created.name}' created by ${user.name}\n${created.description}`,
        url: getRedirectSubdomainPath(context, domain.subdomain, `/process-viewer/${created.id}`)
      })

    return created
  }

  @Directive('@transaction')
  @Mutation(returns => Process, { description: 'To modify Process information' })
  async updateProcess(
    @Arg('id') id: string,
    @Arg('patch') patch: ProcessPatch,
    @Ctx() context: ResolverContext
  ): Promise<Process> {
    const { domain, user, notify, tx } = context.state
    const repository = tx.getRepository(Process)

    const process = await repository.findOneBy({ 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=='
      }
    }

    if (patch.groupId !== undefined) {
      const groupRepository = tx.getRepository(ProcessGroup)
      process.group =
        (await groupRepository.findOneBy({
          domain: { id: domain.id },
          id: patch.groupId
        })) || null

      delete patch.groupId
    }

    const updated = await repository.save({
      ...process,
      ...patch,
      updater: user
    })

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

    return updated
  }

  @Directive('@transaction')
  @Mutation(returns => Boolean, { description: 'To delete Process' })
  async deleteProcess(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
    const { domain, user, notify, tx } = context.state
    const repository = tx.getRepository(Process)
    const process = await repository.findOneBy({ domain: { id: domain.id }, id })

    const deleted = await repository.delete(id)

    notify &&
      notify({
        mode: 'in-app',
        title: `Process '${process.name}' deleted`,
        body: `Process '${process.name}' deleted by ${user.name}\n${process.description}`
      })

    return true
  }
}
