import type {Prisma, Tag} from '@/generated/prisma/client'
import {prismaClient} from './prismaClient'
import type {TagWithContacts} from '@/models/tags'
import {tagWithContactsInclude} from '@/models/tags'

export type CreateTagParams = Prisma.TagUncheckedCreateInput

/**
 * Create a new tag.
 */
export async function createTag(tagInput: CreateTagParams): Promise<Tag> {
  return prismaClient.tag.create({data: tagInput})
}

/**
 * Retrieve all tags.
 */
export async function getTags(userId: string): Promise<Tag[]> {
  return prismaClient.tag.findMany({where: {userId}})
}

/**
 * Get a specific tag from the database.
 *
 * @param id The id of the tag to retrieve.
 * @param userId The id of the user to whom the tag belongs.
 */
export async function getTag(id: string, userId: string): Promise<TagWithContacts> {
  return prismaClient.tag.findUniqueOrThrow({
    where: {id, userId},
    include: tagWithContactsInclude,
  })
}

/**
 * Delete a tag.
 *
 * @param id The id of the tag to delete.
 * @param userId The id of the user to whom the tag belongs.
 */
export async function deleteTag(id: string, userId: string): Promise<void> {
  await prismaClient.tag.delete({where: {id, userId}})
}

export type UpdateTagParams = Prisma.TagUpdateInput & {id: string}

/**
 * Update a tag.
 *
 * @param id The id of the tag to update.
 * @param tag The updated tag information.
 * @param userId The id of the user to whom the tag belongs.
 */
export async function updateTag({id, ...tag}: UpdateTagParams, userId: string): Promise<Tag> {
  return prismaClient.tag.update({where: {id, userId}, data: tag})
}

/**
 * Link a tag to a contact.
 *
 * @param tagId The id of the tag for which to link the contacts.
 * @param contactIds The ids of the contacts to connect to the tag.
 * @param userId The id of the user to whom the tag belongs.
 */
export async function linkTagsToContact(tagId: string, contactIds: string[], userId: string): Promise<void> {
  await prismaClient.tag.update({
    where: {id: tagId, userId},
    data: {
      contacts: {
        connect: contactIds.map(id => ({id})),
      },
    },
  })
}

/**
 * Remove a tag from a contact.
 *
 * @param tagId The id of the tag from which to remove the contacts.
 * @param contactIds The ids of the contacts to remove from the tag.
 * @param userId The id of the user to whom the tag belongs.
 */
export async function disconnectTagsFromContact(tagId: string, contactIds: string[], userId: string): Promise<void> {
  await prismaClient.tag.update({
    where: {id: tagId, userId},
    data: {
      contacts: {
        disconnect: contactIds.map(id => ({id})),
      },
    },
  })
}
