/**
 * De server-only import (die geïnstalleerd moet worden via pnpm) zorgt ervoor dat de code in dit bestand enkel op de
 * server uitgevoerd kan worden.
 * Als één van de geëxporteerde functies geïmporteerd wordt in een client component of hook zal de applicatie niet
 * compileren en een foutmelding opgooien.
 */
import 'server-only'
import {prismaClient} from './prismaClient'
import type {Contact, Prisma} from '@/generated/prisma/client'
import {toggleFavoriteQuery} from '@/generated/prisma/sql/toggleFavoriteQuery'

export type CreateContactParams = Prisma.ContactUncheckedCreateInput

/**
 * Create a new contact for the currently logged-in user.
 *
 * @param userId The id of the user to whom the contact belongs.
 * @param contact The information for the new contact.
 */
export function createContact({userId, ...contact}: CreateContactParams): Promise<Contact> {
  return prismaClient.contact.create({
    data: {
      ...contact,
      user: {
        connect: {id: userId},
      },
    },
  })
}

/**
 * Retrieve the contacts for the currently logged-in user.
 *
 * @param userId The id of the user for whom to retrieve contacts.
 * @param contactName An optional parameter used to filter the contacts.
 */
export function getContacts(userId: string, contactName: string = ''): Promise<Contact[]> {
  return prismaClient.contact.findMany({
    where: {
      userId,
      OR: [
        {firstName: {contains: contactName, mode: 'insensitive'}},
        {lastName: {contains: contactName, mode: 'insensitive'}},
      ],
    },
  }) as Promise<Contact[]>
}

/**
 * Retrieve the contacts which have been added to user's favorites.
 *
 * @param userId The id of the user for whom to retrieve contacts.
 */
export function getFavoriteContacts(userId: string): Promise<Contact[]> {
  return prismaClient.contact.findMany({
    where: {favorite: true, userId},
  })
}

/**
 * Retrieve a single contact.
 *
 * @param id The id of the contact to retrieve.
 * @param userId the id of the user for whom to retrieve contacts.
 */
export function getContact(id: string, userId: string): Promise<Contact> {
  // De findUnique methode geeft een null terug als er geen match gevonden is.
  // De findUniqueOrThrow methode gooit een error als er geen match gevonden is.
  return prismaClient.contact.findUniqueOrThrow({where: {id, userId}})
}

export type UpdateContactParams = Prisma.ContactUncheckedUpdateInput & {id: string; userId: string}

/**
 * Update an existing contact.
 *
 * @param id The id of the contact to update.
 * @param userId The id of the user to whom the contact belongs.
 * @param contact The updated contact info.
 */
export function updateContact({id, userId, ...contact}: UpdateContactParams): Promise<Contact> {
  return prismaClient.contact.update({where: {id, userId}, data: contact})
}

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

/**
 * Toggle the favorite option for a given contact.
 *
 * @param id The id of the contact for which the favorite column must be toggled.
 * @param userId The id of the user to whom the contact belongs.
 */
export async function toggleFavorite(id: string, userId: string): Promise<Contact> {
  const data = await prismaClient.$queryRawTyped(toggleFavoriteQuery(id, userId))
  // Deze cast is nodig omdat de Prisma JSON generator niet werkt met TypedSQL queries.
  return data[0] as Contact
}
