'use client'

import { useMemo } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { rankApiContacts } from '@/lib/contacts/contact-match-score'
import { useAuthReady } from '@/lib/api/use-auth-ready'
import { useIsDemoContacts } from '@/lib/demo/demo-contacts-context'
import { DEMO_CONTACTS_QUERY_ROOT } from '@/lib/demo/demo-contacts-bootstrap'
import { useDemoContactsStore } from '@/lib/demo/demo-contacts-store'
import { apiClient, OfflineError } from '../client'
import type { ApiContact, ApiContactSyncResponse } from '../types'

export const FALLBACK_CONTACT_BOOK_ID = 'contacts'

type ApiContactBook = { id: string; name: string }

type ApiContactsListResponse = {
  contacts: ApiContact[]
  pagination?: {
    page: number
    page_size: number
    total?: number
  }
}

export function normalizeContactBooksResponse(booksRaw: unknown): ApiContactBook[] {
  if (Array.isArray(booksRaw)) return booksRaw as ApiContactBook[]
  if (booksRaw && typeof booksRaw === 'object' && 'address_books' in booksRaw) {
    return (booksRaw as { address_books: ApiContactBook[] }).address_books ?? []
  }
  return []
}

export async function fetchContactByPath(path: string): Promise<ApiContact> {
  const apiPath = path.replace(/^\/+/, '')
  if (useDemoContactsStore.getState().active) {
    const found = useDemoContactsStore
      .getState()
      .contacts.find(
        (contact) =>
          contact.path?.replace(/^\/+/, '') === apiPath ||
          contact.uid === apiPath ||
          contact.uid === path,
      )
    if (found) return found
  }
  return apiClient.get<ApiContact>(`/contacts/${apiPath}`)
}

export async function fetchContactsForBook(bookId: string): Promise<ApiContact[]> {
  const pageSize = 500
  let page = 1
  const all: ApiContact[] = []

  while (page <= 100) {
    const res = await apiClient.get<ApiContact[] | ApiContactsListResponse>(
      `/contacts/books/${bookId}`,
      { page: String(page), page_size: String(pageSize) },
    )
    const batch = Array.isArray(res) ? res : (res.contacts ?? [])
    all.push(...batch)

    if (batch.length < pageSize) break
    const total = !Array.isArray(res) ? res.pagination?.total : undefined
    if (total != null && all.length >= total) break
    page += 1
  }

  return all
}

export function useDefaultContactBookId() {
  const { data: booksRaw, isLoading, isError } = useContactBooks()
  return useMemo(() => {
    if (isLoading || isError) return undefined
    const books = normalizeContactBooksResponse(booksRaw)
    return books[0]?.id ?? FALLBACK_CONTACT_BOOK_ID
  }, [booksRaw, isLoading, isError])
}

export function useContacts(bookId?: string) {
  const { ready, authenticated } = useAuthReady()
  const isDemoContacts = useIsDemoContacts()
  const demoVersion = useDemoContactsStore((s) => s.version)
  const defaultBookId = useDefaultContactBookId()
  const resolvedBookId = bookId ?? defaultBookId

  return useQuery({
    queryKey: isDemoContacts
      ? [...DEMO_CONTACTS_QUERY_ROOT, 'list', resolvedBookId, demoVersion]
      : ['contacts', resolvedBookId],
    queryFn: () => {
      if (isDemoContacts && resolvedBookId) {
        return useDemoContactsStore.getState().listContacts(resolvedBookId)
      }
      return fetchContactsForBook(resolvedBookId!)
    },
    enabled: isDemoContacts ? ready && authenticated && !!resolvedBookId : !!resolvedBookId,
    staleTime: 5 * 60_000,
    initialData:
      isDemoContacts && resolvedBookId
        ? () => useDemoContactsStore.getState().listContacts(resolvedBookId)
        : undefined,
  })
}

export function useContactBooks() {
  const { ready, authenticated } = useAuthReady()
  const isDemoContacts = useIsDemoContacts()
  const demoVersion = useDemoContactsStore((s) => s.version)

  return useQuery({
    queryKey: isDemoContacts
      ? [...DEMO_CONTACTS_QUERY_ROOT, 'books', demoVersion]
      : ['contact-books'],
    queryFn: async () => {
      if (isDemoContacts) {
        return useDemoContactsStore.getState().listBooks()
      }
      const res = await apiClient.get<ApiContactBook[] | { address_books: ApiContactBook[] }>(
        '/contacts/books',
      )
      return normalizeContactBooksResponse(res)
    },
    enabled: isDemoContacts ? ready && authenticated : true,
    staleTime: 10 * 60_000,
    initialData: isDemoContacts
      ? () => useDemoContactsStore.getState().listBooks()
      : undefined,
  })
}

export function useSyncContacts(bookId?: string, syncToken?: string) {
  return useQuery({
    queryKey: ['contacts-sync', bookId, syncToken],
    queryFn: () =>
      apiClient.get<ApiContactSyncResponse>(`/contacts/books/${bookId}/sync`, {
        sync_token: syncToken,
      }),
    enabled: !!bookId && !!syncToken,
  })
}

export function useSearchContacts(query: string) {
  const queryClient = useQueryClient()
  const isDemoContacts = useIsDemoContacts()
  const demoVersion = useDemoContactsStore((s) => s.version)

  return useQuery({
    queryKey: isDemoContacts
      ? [...DEMO_CONTACTS_QUERY_ROOT, 'search', query, demoVersion]
      : ['contacts-search', query],
    queryFn: async () => {
      if (isDemoContacts) {
        return useDemoContactsStore.getState().searchContacts(query)
      }
      try {
        const res = await apiClient.get<ApiContact[] | ApiContactsListResponse>(
          '/contacts/search',
          { q: query },
        )
        const list = Array.isArray(res) ? res : (res.contacts ?? [])
        return rankApiContacts(list, query)
      } catch (err) {
        if (err instanceof OfflineError) {
          const cached = queryClient.getQueriesData<ApiContact[]>({
            queryKey: ['contacts'],
          })
          const allContacts: ApiContact[] = []
          for (const [, data] of cached) {
            if (data) allContacts.push(...data)
          }
          return rankApiContacts(allContacts, query)
        }
        throw err
      }
    },
    enabled: query.length >= 2,
    staleTime: 30_000,
    initialData: isDemoContacts
      ? () => useDemoContactsStore.getState().searchContacts(query)
      : undefined,
  })
}

export function useContactInteractions(email?: string) {
  return useQuery({
    queryKey: ['contact-interactions', email],
    queryFn: () => apiClient.get<unknown>('/contacts/interactions', { email }),
    enabled: !!email,
  })
}
