import { apiContactToFullContact } from '@/lib/api/adapters'
import type { ApiContact } from '@/lib/api/types'
import type { FullContact } from '@/lib/contacts/types'

type BookListCache = {
  apiContacts: ApiContact[]
  fullContacts: FullContact[]
}

const parseCache = new Map<string, FullContact>()
const parseSigCache = new Map<string, string>()
const listCacheByBook = new Map<string, BookListCache>()

function contactCacheKey(api: ApiContact): string {
  return api.uid || api.path || `${api.full_name}:${api.email ?? ''}`
}

function contactSignature(api: ApiContact): string {
  return [
    api.uid,
    api.path,
    api.etag,
    api.full_name,
    api.email,
    api.raw_vcard?.length ?? 0,
  ].join('|')
}

/** Parse vCard une seule fois par contact tant que la signature API est stable. */
export function apiContactToFullContactCached(api: ApiContact): FullContact {
  const key = contactCacheKey(api)
  const sig = contactSignature(api)
  if (parseSigCache.get(key) === sig) {
    const hit = parseCache.get(key)
    if (hit) return hit
  }
  const full = apiContactToFullContact(api)
  parseCache.set(key, full)
  parseSigCache.set(key, sig)
  return full
}

function rebuildFullList(bookId: string, apiContacts: ApiContact[]): FullContact[] {
  const fullContacts = apiContacts.map(apiContactToFullContactCached)
  listCacheByBook.set(bookId, { apiContacts, fullContacts })
  return fullContacts
}

/**
 * Reconstruit la liste complète seulement si nécessaire.
 * Sur ajout en fin de liste (cas courant), réutilise les contacts déjà parsés.
 */
export function mapApiContactsToFullContacts(
  bookId: string,
  apiContacts: ApiContact[] | undefined,
): FullContact[] {
  if (!apiContacts) return []

  const prev = listCacheByBook.get(bookId)
  if (prev && prev.apiContacts === apiContacts) {
    return prev.fullContacts
  }

  if (prev && apiContacts.length === prev.apiContacts.length + 1) {
    let prefixMatch = true
    for (let i = 0; i < prev.apiContacts.length; i++) {
      if (apiContacts[i] !== prev.apiContacts[i]) {
        prefixMatch = false
        break
      }
    }
    if (prefixMatch) {
      const appended = apiContactToFullContactCached(apiContacts[apiContacts.length - 1]!)
      const fullContacts = [...prev.fullContacts, appended]
      listCacheByBook.set(bookId, { apiContacts, fullContacts })
      return fullContacts
    }
  }

  if (
    prev &&
    apiContacts.length === prev.apiContacts.length &&
    apiContacts.every((c, i) => c === prev.apiContacts[i])
  ) {
    return prev.fullContacts
  }

  return rebuildFullList(bookId, apiContacts)
}

export function invalidateContactListCache(bookId?: string) {
  if (bookId) {
    listCacheByBook.delete(bookId)
    return
  }
  listCacheByBook.clear()
  parseCache.clear()
  parseSigCache.clear()
}
