'use client'

import { useMutation, useQueryClient } from '@tanstack/react-query'
import { apiClient, OfflineError } from '../client'
import { enqueue } from '../offline-queue'
import type { Recipient, ApiOutboxMessage, PaginatedResponse } from '../types'
import { useDemoMail } from '@/lib/demo/demo-mail-context'
import { useDemoMailStore } from '@/lib/demo/demo-mail-store'

export interface SendMessagePayload {
  account_id: string
  to: Recipient[]
  cc?: Recipient[]
  bcc?: Recipient[]
  subject: string
  body_html: string
  in_reply_to?: string
  idempotency_key: string
  scheduled_at?: string
}

export type DraftPayload = Omit<SendMessagePayload, 'idempotency_key' | 'scheduled_at'>

export function useSendMessage() {
  const queryClient = useQueryClient()
  const demoMail = useDemoMail()

  return useMutation({
    mutationFn: async (payload: SendMessagePayload) => {
      if (demoMail) {
        const created = useDemoMailStore.getState().sendMessage(payload)
        demoMail.notify('Message « envoyé »')
        return {
          id: created.id,
          account_id: created.account_id,
          status: 'sent',
          to: created.to,
          subject: created.subject,
          body_html: created.body_html ?? '',
          created_at: created.date,
        } satisfies ApiOutboxMessage
      }
      try {
        return await apiClient.post<ApiOutboxMessage>('/mail/send', payload)
      } catch (err) {
        if (err instanceof OfflineError) {
          await enqueue({
            id: payload.idempotency_key,
            timestamp: Date.now(),
            type: 'send_message',
            payload,
            retries: 0,
          })
          return null
        }
        throw err
      }
    },
    onSuccess: () => {
      if (demoMail) {
        useDemoMailStore.getState().bump()
      }
      queryClient.invalidateQueries({ queryKey: ['messages', 'sent'] })
    },
  })
}

export function useCreateDraft() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (payload: DraftPayload) => {
      try {
        return await apiClient.post<ApiOutboxMessage>('/mail/drafts', payload)
      } catch (err) {
        if (err instanceof OfflineError) {
          await enqueue({
            id: `draft-create-${Date.now()}`,
            timestamp: Date.now(),
            type: 'create_draft',
            payload,
            retries: 0,
          })
          return null
        }
        throw err
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['messages', 'drafts'] })
    },
  })
}

export function useUpdateDraft() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ id, ...payload }: DraftPayload & { id: string }) => {
      try {
        return await apiClient.put<ApiOutboxMessage>(`/mail/drafts/${id}`, payload)
      } catch (err) {
        if (err instanceof OfflineError) {
          await enqueue({
            id: `draft-update-${id}-${Date.now()}`,
            timestamp: Date.now(),
            type: 'update_draft',
            payload: { draft_id: id, ...payload },
            retries: 0,
          })
          return null
        }
        throw err
      }
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({ queryKey: ['messages', 'drafts'] })
      queryClient.invalidateQueries({ queryKey: ['message', variables.id] })
    },
  })
}

export function useDeleteDraft() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ id }: { id: string }) => {
      try {
        await apiClient.delete(`/mail/drafts/${id}`)
      } catch (err) {
        if (err instanceof OfflineError) {
          await enqueue({
            id: `draft-delete-${id}-${Date.now()}`,
            timestamp: Date.now(),
            type: 'delete_draft',
            payload: { draft_id: id },
            retries: 0,
          })
          return
        }
        throw err
      }
    },
    onMutate: async ({ id }) => {
      await queryClient.cancelQueries({ queryKey: ['messages', 'drafts'] })

      const previous = queryClient.getQueriesData<PaginatedResponse<ApiOutboxMessage>>({
        queryKey: ['messages', 'drafts'],
      })

      queryClient.setQueriesData<PaginatedResponse<ApiOutboxMessage>>(
        { queryKey: ['messages', 'drafts'] },
        (old) => {
          if (!old) return old
          return { ...old, data: old.data.filter((m) => m.id !== id) }
        }
      )

      return { previous }
    },
    onError: (_err, _vars, context) => {
      context?.previous?.forEach(([key, data]) => queryClient.setQueryData(key, data))
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['messages', 'drafts'] })
    },
  })
}

export function useScheduleSend() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (payload: SendMessagePayload & { scheduled_at: string }) => {
      try {
        return await apiClient.post<ApiOutboxMessage>('/mail/send', payload)
      } catch (err) {
        if (err instanceof OfflineError) {
          await enqueue({
            id: payload.idempotency_key,
            timestamp: Date.now(),
            type: 'schedule_send',
            payload,
            retries: 0,
          })
          return null
        }
        throw err
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['outbox'] })
    },
  })
}

export function useRescheduleSend() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ id, scheduled_at }: { id: string; scheduled_at: string }) => {
      return await apiClient.post<ApiOutboxMessage>(`/mail/outbox/${id}/reschedule`, {
        scheduled_at,
      })
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['outbox'] })
    },
  })
}

export function useCancelScheduled() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ id }: { id: string }) => {
      return await apiClient.post<ApiOutboxMessage>(`/mail/outbox/${id}/cancel`)
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['outbox'] })
    },
  })
}

export function useSendNow() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ id }: { id: string }) => {
      return await apiClient.post<ApiOutboxMessage>(`/mail/outbox/${id}/send-now`)
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['outbox'] })
      queryClient.invalidateQueries({ queryKey: ['messages', 'sent'] })
    },
  })
}
