import type {UseMutationResult, UseSuspenseQueryResult} from '@tanstack/react-query'
import {useMutation, useQueryClient, useSuspenseQuery} from '@tanstack/react-query'
import type {IContact} from '@/models/IContact.ts'

//region Mutations & queries

/**
 * ---------------------------------------------------------------------------------------------------------------------
 *                                          MUTATIONS & QUERIES
 * ---------------------------------------------------------------------------------------------------------------------
 */

export const useGetContacts = (): UseSuspenseQueryResult<IContact[], Error> => {
  return useSuspenseQuery({
    queryKey: ['contacts'],
    queryFn: () => getContacts(),
  })
}

export const useGetContact = (id: string): UseSuspenseQueryResult<IContact, Error> => {
  return useSuspenseQuery({
    queryKey: ['contacts', id],
    queryFn: () => getContact(id),
  })
}

export const useCreateContact = (): UseMutationResult<IContact, Error, CreateContactParams, void> => {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: createContact,
    onSuccess: async () => {
      await queryClient.invalidateQueries({queryKey: ['contacts']})
    },
  })
}

export const useDeleteContact = (): UseMutationResult<void, Error, string, void> => {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: deleteContact,
    onSuccess: async (_, id) => {
      await queryClient.invalidateQueries({queryKey: ['contacts']})
      await queryClient.invalidateQueries({queryKey: ['contacts', id]})
    },
  })
}

export const useUpdateContact = (): UseMutationResult<IContact, Error, Partial<IContact> & {id: string}, void> => {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: updateContact,
    onSuccess: async (_, {id}) => {
      await queryClient.invalidateQueries({queryKey: ['contacts']})
      await queryClient.invalidateQueries({queryKey: ['contacts', id]})
    },
  })
}

//endregion

//region API functions

/**
 * ---------------------------------------------------------------------------------------------------------------------
 *                                          API functions
 * ---------------------------------------------------------------------------------------------------------------------
 */

async function getContacts(): Promise<IContact[]> {
  const result = await fetch(`http://localhost:3000/api/contacts`)

  if (!result.ok) {
    throw new Error('Failed to fetch contacts')
  }

  return (await result.json()) as IContact[]
}

async function getContact(id: string): Promise<IContact> {
  const result = await fetch(`http://localhost:3000/api/contacts/${id}`)

  if (!result.ok) {
    throw new Error('Failed to fetch contacts')
  }

  return (await result.json()) as IContact
}

interface CreateContactParams {
  firstName: string
  lastName?: string
  contactInfo: Array<{
    type: string
    value: string
  }>
}

async function createContact(contact: CreateContactParams): Promise<IContact> {
  const result = await fetch(`http://localhost:3000/api/contacts`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(contact),
  })

  if (!result.ok) {
    throw new Error('Failed to create contact')
  }

  return (await result.json()) as IContact
}

async function updateContact(contact: Partial<IContact> & {id: string}): Promise<IContact> {
  const result = await fetch(`http://localhost:3000/api/contacts/${contact.id}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(contact),
  })

  if (!result.ok) {
    throw new Error('Failed to update contact')
  }

  return (await result.json()) as IContact
}

async function deleteContact(contactId: string): Promise<void> {
  const result = await fetch(`http://localhost:3000/api/contacts/${contactId}`, {
    method: 'DELETE',
  })

  if (!result.ok) {
    throw new Error('Failed to delete contact')
  }
}

//endregion
