import { ref } from 'vue'
import { useToast } from './useToast'
import { useApi } from './useApi'
import { humanizeError } from '~/shared/utils/errorMessages'
import { uniqueConstructeurIds } from '~/shared/constructeurUtils'
import { useConstructeurs, type Constructeur } from './useConstructeurs'
import { extractRelationId, normalizeRelationIds } from '~/shared/apiRelations'
import { extractCollection, extractTotal } from '~/shared/utils/apiHelpers'

export interface Product {
  id: string
  name: string
  reference?: string | null
  typeProductId?: string | null
  typeProduct?: { id: string; name?: string } | null
  constructeurs?: Constructeur[]
  constructeurIds?: string[]
  supplierPrice?: number | null
  createdAt?: string | null
  updatedAt?: string | null
  documents?: unknown[]
  [key: string]: unknown
}

interface ProductListResult {
  success: boolean
  data?: { items: Product[]; total: number; page: number; itemsPerPage: number }
  error?: string
}

interface ProductSingleResult {
  success: boolean
  data?: Product
  error?: string
}

interface LoadProductsOptions {
  search?: string
  page?: number
  itemsPerPage?: number
  orderBy?: string
  orderDir?: 'asc' | 'desc'
  typeName?: string
  typeProductId?: string
  force?: boolean
}

const products = ref<Product[]>([])
const total = ref(0)
const loading = ref(false)
const loaded = ref(false)
const error = ref<string | null>(null)

const replaceInCache = (item: Product): boolean => {
  if (!item?.id) {
    return false
  }
  const index = products.value.findIndex((product) => product.id === item.id)
  if (index === -1) {
    products.value.unshift(item)
    return true
  }
  const clone = products.value.slice()
  clone[index] = item
  products.value = clone
  return false
}

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

  const withResolvedConstructeurs = async (product: Product): Promise<Product> => {
    if (!product || typeof product !== 'object') {
      return product
    }
    if (!product.typeProductId) {
      const typeProductId = extractRelationId(product.typeProduct)
      if (typeProductId) {
        product.typeProductId = typeProductId
      }
    }
    const ids = uniqueConstructeurIds(
      product.constructeurIds,
      product.constructeurs,
    )
    const hasResolvedConstructeurs =
      Array.isArray(product.constructeurs) &&
      product.constructeurs.length > 0 &&
      product.constructeurs.every((item) => item && typeof item === 'object')

    if (ids.length && !hasResolvedConstructeurs) {
      const resolved = await ensureConstructeurs(ids)
      if (resolved.length) {
        product.constructeurs = resolved
        product.constructeurIds = ids
      }
    }
    return product
  }

  const loadProducts = async (options: LoadProductsOptions = {}): Promise<ProductListResult> => {
    const {
      search = '',
      page = 1,
      itemsPerPage = 30,
      orderBy = 'name',
      orderDir = 'asc',
      typeName,
      typeProductId,
      force = false,
    } = options

    if (!force && loaded.value && !search && !typeName && !typeProductId && page === 1) {
      return {
        success: true,
        data: { items: products.value, total: total.value, page, itemsPerPage },
      }
    }

    if (!typeProductId && loading.value) {
      return {
        success: true,
        data: { items: products.value, total: total.value, page, itemsPerPage },
      }
    }

    loading.value = true
    error.value = null
    try {
      const params = new URLSearchParams()
      params.set('itemsPerPage', String(itemsPerPage))
      params.set('page', String(page))

      if (search && search.trim()) {
        params.set('search', search.trim())
      }

      if (typeName && typeName.trim()) {
        params.set('typeProduct.name', typeName.trim())
      }

      if (typeProductId) {
        params.set('typeProduct', typeProductId)
      }

      params.set(`order[${orderBy}]`, orderDir)

      const result = await get(`/products?${params.toString()}`)
      if (result.success) {
        const items = extractCollection(result.data)
        const enrichedItems = await Promise.all(items.map((item) => withResolvedConstructeurs(item)))
        const resultTotal = extractTotal(result.data, items.length)

        if (!typeProductId) {
          products.value = enrichedItems
          total.value = resultTotal
          loaded.value = true
        }

        return {
          success: true,
          data: {
            items: enrichedItems,
            total: resultTotal,
            page,
            itemsPerPage,
          },
        }
      } else if (result.error) {
        error.value = result.error
        showError(`Impossible de charger les produits: ${result.error}`)
      }
      return result as ProductListResult
    } catch (err) {
      console.error('Erreur lors du chargement des produits:', err)
      const message = humanizeError((err as Error)?.message)
      error.value = message
      showError(`Impossible de charger les produits.`)
      return { success: false, error: message }
    } finally {
      loading.value = false
    }
  }

  const createProduct = async (payload: Partial<Product>): Promise<ProductSingleResult> => {
    const { constructeurIds, constructeurs, constructeurId, constructeur, ...cleanPayload } = payload as any
    const normalizedPayload = normalizeRelationIds(cleanPayload)
    loading.value = true
    error.value = null
    try {
      const result = await post('/products', normalizedPayload)
      if (result.success && result.data) {
        const enriched = await withResolvedConstructeurs(result.data as Product)
        const added = replaceInCache(enriched)
        if (added) {
          total.value += 1
        }
        return { success: true, data: enriched }
      } else if (result.error) {
        error.value = result.error
        showError(result.error)
      }
      return { success: false, error: result.error }
    } catch (err) {
      console.error('Erreur lors de la création du produit:', err)
      const message = humanizeError((err as Error)?.message)
      error.value = message
      showError('Impossible de créer le produit.')
      return { success: false, error: message }
    } finally {
      loading.value = false
    }
  }

  const updateProduct = async (id: string, payload: Partial<Product>): Promise<ProductSingleResult> => {
    const { constructeurIds, constructeurs, constructeurId, constructeur, ...cleanPayload } = payload as any
    const normalizedPayload = normalizeRelationIds(cleanPayload)
    loading.value = true
    error.value = null
    try {
      const result = await patch(`/products/${id}`, normalizedPayload)
      if (result.success && result.data) {
        const enriched = await withResolvedConstructeurs(result.data as Product)
        replaceInCache(enriched)
        return { success: true, data: enriched }
      } else if (result.error) {
        error.value = result.error
        showError(result.error)
      }
      return { success: false, error: result.error }
    } catch (err) {
      console.error('Erreur lors de la mise à jour du produit:', err)
      const message = humanizeError((err as Error)?.message)
      error.value = message
      showError('Impossible de mettre à jour le produit.')
      return { success: false, error: message }
    } finally {
      loading.value = false
    }
  }

  const deleteProduct = async (id: string): Promise<ProductSingleResult> => {
    loading.value = true
    error.value = null
    try {
      const result = await del(`/products/${id}`)
      if (result.success) {
        products.value = products.value.filter((product) => product.id !== id)
        total.value = Math.max(0, total.value - 1)
        return { success: true }
      } else if (result.error) {
        error.value = result.error
        showError(result.error)
      }
      return { success: false, error: result.error }
    } catch (err) {
      console.error('Erreur lors de la suppression du produit:', err)
      const message = humanizeError((err as Error)?.message)
      error.value = message
      showError('Impossible de supprimer le produit.')
      return { success: false, error: message }
    } finally {
      loading.value = false
    }
  }

  const getProduct = async (id: string, options: { force?: boolean } = {}): Promise<ProductSingleResult> => {
    const shouldForce = !!options.force
    if (!shouldForce) {
      const cached = products.value.find((product) => product.id === id)
      if (cached && Array.isArray(cached.constructeurs) && cached.constructeurs.length > 0) {
        return { success: true, data: cached }
      }
    }

    try {
      const result = await get(`/products/${id}`)
      if (result.success && result.data) {
        const enriched = await withResolvedConstructeurs(result.data as Product)
        replaceInCache(enriched)
        return { success: true, data: enriched }
      }
      return { success: false, error: result.error }
    } catch (err) {
      console.error('Erreur lors du chargement du produit:', err)
      const message = (err as Error)?.message ?? 'Erreur inconnue'
      return { success: false, error: message }
    }
  }

  const clearProductsCache = () => {
    products.value = []
    total.value = 0
    loaded.value = false
    error.value = null
  }

  return {
    products,
    total,
    loading,
    loaded,
    error,
    loadProducts,
    createProduct,
    updateProduct,
    deleteProduct,
    getProduct,
    clearProductsCache,
  }
}
