import { ref } from 'vue'
import { useApi } from './useApi'
import { useToast } from './useToast'
import { extractCollection, extractTotal } from '~/shared/utils/apiHelpers'

export interface ConstructeurTelephone {
  '@id'?: string
  id?: string
  numero: string
  label?: string | null
}

export interface ConstructeurCategorieRef {
  '@id'?: string
  id: string
  name: string
}

export interface Constructeur {
  '@id'?: string
  id: string
  name: string
  email?: string | null
  telephones?: ConstructeurTelephone[]
  categories?: ConstructeurCategorieRef[]
  createdAt?: string
  updatedAt?: string
}

interface ConstructeurResult {
  success: boolean
  data?: Constructeur | Constructeur[]
  error?: string
}

export interface ConstructeurPageOptions {
  page?: number
  itemsPerPage?: number
  search?: string
  categoryId?: string
  orderField?: 'name' | 'email' | 'createdAt'
  orderDirection?: 'asc' | 'desc'
}

export interface ConstructeurPageResult {
  success: boolean
  items: Constructeur[]
  totalItems: number
  totalPages: number
  currentPage: number
  error?: string
}

const constructeurs = ref<Constructeur[]>([])
const loading = ref(false)
const loaded = ref(false)

const uniqueConstructeurs = (items: Constructeur[] = []): Constructeur[] => {
  const map = new Map<string, Constructeur>()
  items.forEach((item) => {
    if (item && typeof item === 'object' && typeof item.id === 'string') {
      map.set(item.id, item)
    }
  })
  return Array.from(map.values())
}

const normalizeIds = (ids: unknown[] = []): string[] => {
  if (!Array.isArray(ids)) {
    return []
  }
  return Array.from(
    new Set(
      ids
        .map((value) => (typeof value === 'string' ? value.trim() : ''))
        .filter((value) => value.length > 0),
    ),
  )
}

const upsertConstructeurs = (items: Constructeur[] = []) => {
  if (!Array.isArray(items) || !items.length) {
    return
  }
  const merged = uniqueConstructeurs([...constructeurs.value, ...items])
  constructeurs.value = merged
}

const getIndexedConstructeur = (id: string): Constructeur | null =>
  constructeurs.value.find((item) => item && item.id === id) || null

const pendingFetches = new Map<string, Promise<Constructeur | null>>()

export function useConstructeurs() {
  const { get, post, patch, delete: del } = useApi()
  const { showSuccess, showError } = useToast()

  const loadConstructeurs = async (search = '', options: { force?: boolean } = {}): Promise<ConstructeurResult> => {
    if (!search && !options.force && loaded.value) {
      return { success: true, data: constructeurs.value }
    }
    loading.value = true
    try {
      const params = new URLSearchParams()
      params.set('itemsPerPage', '2000')
      if (search) params.set('search', search)
      const result = await get(`/constructeurs?${params.toString()}`)
      if (result.success) {
        const items = extractCollection(result.data)
        constructeurs.value = uniqueConstructeurs(items)
        if (!search) loaded.value = true
      }
      return result as ConstructeurResult
    } catch (error) {
      const err = error as Error
      console.error('Erreur lors du chargement des fournisseurs:', error)
      return { success: false, error: err.message }
    } finally {
      loading.value = false
    }
  }

  const searchConstructeurs = async (search = ''): Promise<ConstructeurResult> => {
    return loadConstructeurs(search)
  }

  const fetchConstructeursPage = async (opts: ConstructeurPageOptions = {}): Promise<ConstructeurPageResult> => {
    const page = Math.max(1, opts.page ?? 1)
    const itemsPerPage = Math.max(1, opts.itemsPerPage ?? 30)
    loading.value = true
    try {
      const params = new URLSearchParams()
      params.set('page', String(page))
      params.set('itemsPerPage', String(itemsPerPage))
      if (opts.search && opts.search.trim()) params.set('search', opts.search.trim())
      if (opts.categoryId) params.set('categories.id', opts.categoryId)
      if (opts.orderField) {
        params.set(`order[${opts.orderField}]`, opts.orderDirection ?? 'asc')
      }
      const result = await get(`/constructeurs?${params.toString()}`)
      if (!result.success) {
        return { success: false, items: [], totalItems: 0, totalPages: 0, currentPage: page, error: result.error }
      }
      const items = extractCollection<Constructeur>(result.data)
      const totalItems = extractTotal(result.data, items.length)
      const totalPages = Math.max(1, Math.ceil(totalItems / itemsPerPage))
      upsertConstructeurs(items)
      return { success: true, items, totalItems, totalPages, currentPage: page }
    } catch (error) {
      const err = error as Error
      console.error('Erreur lors du chargement de la page fournisseurs:', error)
      return { success: false, items: [], totalItems: 0, totalPages: 0, currentPage: page, error: err.message }
    } finally {
      loading.value = false
    }
  }

  const createConstructeur = async (data: Record<string, unknown>): Promise<ConstructeurResult> => {
    loading.value = true
    try {
      const result = await post('/constructeurs', data)
      if (result.success) {
        upsertConstructeurs([result.data as Constructeur])
        showSuccess(`Fournisseur "${(result.data as Constructeur).name}" créé`)
      } else if (result.error) {
        showError(result.error)
      }
      return result as ConstructeurResult
    } catch (error) {
      const err = error as Error
      console.error('Erreur lors de la création du fournisseur:', error)
      showError('Impossible de créer le fournisseur')
      return { success: false, error: err.message }
    } finally {
      loading.value = false
    }
  }

  const ensureConstructeurs = async (ids: unknown[] = []): Promise<Constructeur[]> => {
    const normalizedIds = normalizeIds(ids)
    if (!normalizedIds.length) {
      return []
    }

    const collected: Constructeur[] = []
    const missing: string[] = []
    normalizedIds.forEach((id) => {
      const existing = getIndexedConstructeur(id)
      if (existing) {
        collected.push(existing)
      } else {
        missing.push(id)
      }
    })

    if (missing.length) {
      const fetchTasks = missing.map((id) => {
        const cached = pendingFetches.get(id)
        if (cached) {
          return cached
        }
        const task = get(`/constructeurs/${id}`)
          .then((result) => {
            if (result.success && result.data) {
              return result.data as Constructeur
            }
            return null
          })
          .catch((error) => {
            console.error('Erreur lors du chargement du fournisseur:', error)
            return null
          })
          .finally(() => {
            pendingFetches.delete(id)
          })
        pendingFetches.set(id, task)
        return task
      })

      const fetched = await Promise.all(fetchTasks)
      const validFetched = fetched.filter((item): item is Constructeur => item !== null && item.id !== undefined)
      if (validFetched.length) {
        upsertConstructeurs(validFetched)
      }
    }

    return normalizedIds
      .map((id) => getIndexedConstructeur(id))
      .filter((item): item is Constructeur => item !== null)
  }

  const updateConstructeur = async (id: string, data: Record<string, unknown>): Promise<ConstructeurResult> => {
    loading.value = true
    try {
      const result = await patch(`/constructeurs/${id}`, data)
      if (result.success) {
        upsertConstructeurs([result.data as Constructeur])
        showSuccess(`Fournisseur "${(result.data as Constructeur).name}" mis à jour`)
      } else if (result.error) {
        showError(result.error)
      }
      return result as ConstructeurResult
    } catch (error) {
      const err = error as Error
      console.error('Erreur lors de la mise à jour du fournisseur:', error)
      showError('Impossible de mettre à jour le fournisseur')
      return { success: false, error: err.message }
    } finally {
      loading.value = false
    }
  }

  const deleteConstructeur = async (id: string): Promise<ConstructeurResult> => {
    loading.value = true
    try {
      const result = await del(`/constructeurs/${id}`)
      if (result.success) {
        constructeurs.value = constructeurs.value.filter((item) => item.id !== id)
        showSuccess('Fournisseur supprimé')
      } else if (result.error) {
        showError(result.error)
      }
      return result as ConstructeurResult
    } catch (error) {
      const err = error as Error
      console.error('Erreur lors de la suppression du fournisseur:', error)
      showError('Impossible de supprimer le fournisseur')
      return { success: false, error: err.message }
    } finally {
      loading.value = false
    }
  }

  const getConstructeurById = (id: string) => getIndexedConstructeur(id)

  return {
    constructeurs,
    loading,
    loadConstructeurs,
    searchConstructeurs,
    fetchConstructeursPage,
    createConstructeur,
    updateConstructeur,
    deleteConstructeur,
    getConstructeurById,
    ensureConstructeurs,
  }
}
