export function useStrapi(endpoint, options = {}) {
  const queryString = computed(() => {
    const locale = unref(options.locale) ?? "fr-FR"
    const sort = unref(options.sort) ?? null
    const pageSize = unref(options.pageSize) ?? null
    const populate = unref(options.populate) ?? null
    const filters = unref(options.filters) ?? null

    const query = new URLSearchParams()
    query.set("locale", locale)
    if (sort) {
      query.set("sort[0]", sort)
    }
    if (typeof pageSize === "number") {
      query.set("pagination[pageSize]", String(pageSize))
    }
    if (populate && typeof populate === "object") {
      appendPopulate(query, populate)
    }
    if (filters && typeof filters === "object") {
      appendFilters(query, filters)
    }

    return query.toString()
  })

  const fetchAll = computed(() => Boolean(unref(options.fetchAll)))

  const asyncDataKey = computed(() => `${endpoint}:${queryString.value}:fetchAll=${fetchAll.value}`)

  const { data, pending, error, refresh } = useAsyncData(
    asyncDataKey,
    async () => {
      const baseUrl = `${endpoint}?${queryString.value}`

      if (!fetchAll.value) {
        return await $fetch(baseUrl)
      }

      const firstPage = await $fetch(addPageParam(baseUrl, 1))
      const pageCount = Number(firstPage?.meta?.pagination?.pageCount || 1)

      if (pageCount <= 1) {
        return firstPage
      }

      const otherPages = await Promise.all(
        Array.from({ length: pageCount - 1 }, (_, index) => $fetch(addPageParam(baseUrl, index + 2)))
      )

      return {
        ...firstPage,
        data: [
          ...(Array.isArray(firstPage?.data) ? firstPage.data : []),
          ...otherPages.flatMap((page) => (Array.isArray(page?.data) ? page.data : [])),
        ],
      }
    },
    {
      server: true,
      watch: [queryString, fetchAll],
    }
  )

  const items = computed(() => {
    const raw = data.value?.data
    let list = []
    if (Array.isArray(raw)) {
      list = raw.map(normalizeStrapiItem)
    } else if (raw && typeof raw === "object") {
      list = [normalizeStrapiItem(raw)]
    }

    const limit = unref(options.limit)
    if (typeof limit === "number") {
      list = list.slice(0, Math.max(0, limit))
    }

    return list
  })

  return {
    items,
    pending,
    error,
    refresh,
  }
}

function addPageParam(url, page) {
  const separator = url.includes("?") ? "&" : "?"
  return `${url}${separator}pagination[page]=${page}`
}

function appendPopulate(query, populate, prefix = "populate") {
  Object.entries(populate).forEach(([key, value]) => {
    if (value === true) {
      query.set(`${prefix}[${key}]`, "true")
      return
    }
    if (value && typeof value === "object") {
      appendPopulate(query, value, `${prefix}[${key}][populate]`)
    }
  })
}

function appendFilters(query, filters, prefix = "filters") {
  Object.entries(filters).forEach(([key, value]) => {
    if (value === null || value === undefined) return
    if (typeof value !== "object") {
      query.set(`${prefix}[${key}]`, String(value))
      return
    }
    Object.entries(value).forEach(([k, v]) => {
      if (v === null || v === undefined) return
      if (typeof v !== "object") {
        query.set(`${prefix}[${key}][${k}]`, String(v))
        return
      }
      appendFilters(query, v, `${prefix}[${key}][${k}]`)
    })
  })
}

function normalizeStrapiItem(item) {
  const a = item.attributes || item || {}

  return {
    id: item.id,
    ...a,
  }
}
