"use client"

import { create } from "zustand"
import { persist } from "zustand/middleware"
import { debouncedPersistJSONStorage } from "@/lib/stores/debounced-json-storage"
import {
  findDuplicatePairs,
  mergePairKey,
  normalizePhone,
  type DuplicateMatchReason,
} from "./duplicate-detection"
import { MOCK_FULL_CONTACTS } from "./mock-data"
import type { FullContact } from "./types"

type ContactsView = "list" | "view" | "create" | "edit"

/** Prefill for "Nouveau contact" opened from hover card / elsewhere. */
export type ContactCreateDraft = {
  firstName?: string
  lastName?: string
  emails?: { value: string; label: string }[]
}

export interface DeletedContact {
  contact: FullContact
  deletedAt: number
  reason: string
}

export interface MergeSuggestion {
  contactA: FullContact
  contactB: FullContact
  reason: DuplicateMatchReason
}

export interface CoordinateSuggestion {
  contact: FullContact
  suggestedField: string
  suggestedValue: string
}

interface ContactsState {
  contacts: FullContact[]
  deletedContacts: DeletedContact[]
  ignoredMergePairs: string[]
  panelOpen: boolean
  view: ContactsView
  activeContactId: string | null
  searchQuery: string
  searchMode: boolean
  createDraft: ContactCreateDraft | null
}

interface ContactsActions {
  togglePanel: () => void
  openPanel: () => void
  closePanel: () => void
  openContactDetail: (contactId: string) => void
  openCreateContact: (draft?: ContactCreateDraft | null) => void
  clearCreateDraft: () => void
  setView: (view: ContactsView, activeContactId?: string | null) => void
  showContactsList: () => void
  setSearchQuery: (q: string) => void
  setSearchMode: (active: boolean) => void
  addContact: (
    contact: Omit<FullContact, "id" | "createdAt" | "updatedAt">
  ) => string
  addContacts: (
    contacts: Omit<FullContact, "id" | "createdAt" | "updatedAt">[]
  ) => number
  updateContact: (id: string, patch: Partial<FullContact>) => void
  deleteContact: (id: string) => void
  softDeleteContact: (id: string, reason?: string) => void
  restoreContact: (id: string) => void
  emptyTrash: () => void
  mergeContacts: (keepId: string, mergeId: string) => void
  ignoreMergePair: (idA: string, idB: string) => void
  getMergeSuggestions: () => MergeSuggestion[]
  getCoordinateSuggestions: () => CoordinateSuggestion[]
}

export type ContactsStore = ContactsState & ContactsActions

function computeCoordinateSuggestions(contacts: FullContact[]): CoordinateSuggestion[] {
  const suggestions: CoordinateSuggestion[] = []
  const emailDomains = new Map<string, { company?: string; jobTitle?: string }>()

  for (const c of contacts) {
    if (c.company) {
      for (const e of c.emails) {
        const domain = e.value.split("@")[1]?.toLowerCase()
        if (domain && !domain.includes("gmail") && !domain.includes("outlook") && !domain.includes("yahoo") && !domain.includes("proton")) {
          emailDomains.set(domain, { company: c.company, jobTitle: c.jobTitle })
        }
      }
    }
  }

  for (const c of contacts) {
    if (c.company) continue
    for (const e of c.emails) {
      const domain = e.value.split("@")[1]?.toLowerCase()
      if (domain && emailDomains.has(domain)) {
        const info = emailDomains.get(domain)!
        if (info.company) {
          suggestions.push({ contact: c, suggestedField: "company", suggestedValue: info.company })
          break
        }
      }
    }
    if (suggestions.length >= 20) break
  }
  return suggestions
}

export const useContactsStore = create<ContactsStore>()(
  persist(
    (set, get) => ({
      contacts: MOCK_FULL_CONTACTS,
      deletedContacts: [],
      ignoredMergePairs: [],
      panelOpen: false,
      view: "list",
      activeContactId: null,
      searchQuery: "",
      searchMode: false,
      createDraft: null,

      togglePanel: () =>
        set((s) =>
          s.panelOpen
            ? {
                panelOpen: false,
                view: "list",
                activeContactId: null,
                searchQuery: "",
                searchMode: false,
                createDraft: null,
              }
            : { panelOpen: true }
        ),

      openPanel: () => set({ panelOpen: true }),

      closePanel: () =>
        set({
          panelOpen: false,
          view: "list",
          activeContactId: null,
          searchQuery: "",
          searchMode: false,
          createDraft: null,
        }),

      openContactDetail: (contactId) =>
        set({
          panelOpen: true,
          view: "view",
          activeContactId: contactId,
          searchQuery: "",
          searchMode: false,
          createDraft: null,
        }),

      openCreateContact: (draft = null) =>
        set({
          panelOpen: true,
          view: "create",
          activeContactId: null,
          searchQuery: "",
          searchMode: false,
          createDraft: draft,
        }),

      clearCreateDraft: () => set({ createDraft: null }),

      setView: (view, activeContactId = null) =>
        set({ view, activeContactId, createDraft: null }),

      showContactsList: () =>
        set({
          view: "list",
          activeContactId: null,
          searchQuery: "",
          searchMode: false,
          createDraft: null,
        }),

      setSearchQuery: (searchQuery) => set({ searchQuery }),

      setSearchMode: (searchMode) =>
        set(searchMode ? { searchMode } : { searchMode, searchQuery: "" }),

      addContact: (contact) => {
        const id = `contact-${crypto.randomUUID()}`
        const now = Date.now()
        const full: FullContact = { ...contact, id, createdAt: now, updatedAt: now }
        set((s) => ({ contacts: [...s.contacts, full] }))
        return id
      },

      addContacts: (incoming) => {
        if (incoming.length === 0) return 0
        const now = Date.now()
        const added = incoming.map((contact) => ({
          ...contact,
          id: `contact-${crypto.randomUUID()}`,
          createdAt: now,
          updatedAt: now,
        }))
        set((s) => ({ contacts: [...s.contacts, ...added] }))
        return added.length
      },

      updateContact: (id, patch) =>
        set((s) => ({
          contacts: s.contacts.map((c) =>
            c.id === id ? { ...c, ...patch, updatedAt: Date.now() } : c
          ),
        })),

      deleteContact: (id) =>
        set((s) => ({
          contacts: s.contacts.filter((c) => c.id !== id),
          activeContactId: s.activeContactId === id ? null : s.activeContactId,
          view: s.activeContactId === id ? "list" : s.view,
        })),

      softDeleteContact: (id, reason = "Supprimé manuellement") =>
        set((s) => {
          const contact = s.contacts.find((c) => c.id === id)
          if (!contact) return s
          return {
            contacts: s.contacts.filter((c) => c.id !== id),
            deletedContacts: [
              ...s.deletedContacts,
              { contact, deletedAt: Date.now(), reason },
            ],
            activeContactId: s.activeContactId === id ? null : s.activeContactId,
            view: s.activeContactId === id ? "list" : s.view,
          }
        }),

      restoreContact: (id) =>
        set((s) => {
          const entry = s.deletedContacts.find((d) => d.contact.id === id)
          if (!entry) return s
          return {
            contacts: [...s.contacts, entry.contact],
            deletedContacts: s.deletedContacts.filter((d) => d.contact.id !== id),
          }
        }),

      emptyTrash: () => set({ deletedContacts: [] }),

      mergeContacts: (keepId, mergeId) =>
        set((s) => {
          const keep = s.contacts.find((c) => c.id === keepId)
          const merge = s.contacts.find((c) => c.id === mergeId)
          if (!keep || !merge) return s

          const mergedEmails = [...keep.emails]
          for (const e of merge.emails) {
            if (!mergedEmails.some((me) => me.value.toLowerCase() === e.value.toLowerCase())) {
              mergedEmails.push(e)
            }
          }
          const mergedPhones = [...keep.phones]
          for (const p of merge.phones) {
            const norm = normalizePhone(p.value)
            if (
              !mergedPhones.some(
                (mp) => normalizePhone(mp.value) === norm && norm.length > 0
              )
            ) {
              mergedPhones.push(p)
            }
          }

          const mergedLabels = [
            ...new Set([...(keep.labels ?? []), ...(merge.labels ?? [])]),
          ]

          const merged: FullContact = {
            ...keep,
            firstName: keep.firstName || merge.firstName,
            lastName: keep.lastName || merge.lastName,
            emails: mergedEmails,
            phones: mergedPhones,
            labels: mergedLabels.length ? mergedLabels : undefined,
            company: keep.company || merge.company,
            jobTitle: keep.jobTitle || merge.jobTitle,
            department: keep.department || merge.department,
            birthday: keep.birthday || merge.birthday,
            avatarUrl: keep.avatarUrl || merge.avatarUrl,
            notes: [keep.notes, merge.notes].filter(Boolean).join("\n") || undefined,
            updatedAt: Date.now(),
          }

          const pairKey = mergePairKey(keepId, mergeId)

          return {
            contacts: s.contacts
              .filter((c) => c.id !== mergeId)
              .map((c) => (c.id === keepId ? merged : c)),
            ignoredMergePairs: s.ignoredMergePairs.includes(pairKey)
              ? s.ignoredMergePairs
              : [...s.ignoredMergePairs, pairKey],
          }
        }),

      ignoreMergePair: (idA, idB) =>
        set((s) => {
          const key = mergePairKey(idA, idB)
          if (s.ignoredMergePairs.includes(key)) return s
          return { ignoredMergePairs: [...s.ignoredMergePairs, key] }
        }),

      getMergeSuggestions: () => {
        const s = get()
        const ignored = new Set(s.ignoredMergePairs)
        return findDuplicatePairs(s.contacts, ignored).map((p) => ({
          contactA: p.contactA,
          contactB: p.contactB,
          reason: p.reason,
        }))
      },

      getCoordinateSuggestions: () => computeCoordinateSuggestions(get().contacts),
    }),
    {
      name: "contacts-store",
      storage: debouncedPersistJSONStorage,
      partialize: (state) => ({
        contacts: state.contacts,
        deletedContacts: state.deletedContacts,
        ignoredMergePairs: state.ignoredMergePairs,
      }),
    }
  )
)
