export const ok = (data, meta) => ({ data, meta })

export const paginate = (items, query) => {
  const page = Number(query.page || 1)
  const perPage = Number(query.perPage || 10)
  const total = items.length
  const lastPage = Math.max(1, Math.ceil(total / perPage))
  const start = (page - 1) * perPage
  const sliced = items.slice(start, start + perPage)
  return {
    data: sliced,
    meta: { page, perPage, total, lastPage, currentPage: page },
  }
}

const stringIncludes = (haystack, needle) =>
  String(haystack ?? '')
    .toLowerCase()
    .includes(String(needle ?? '').toLowerCase())

export const filterItems = (items, query, rules = {}) =>
  items.filter((item) => {
    for (const [key, rule] of Object.entries(rules)) {
      const value = query[key]
      if (value === '' || value == null) continue
      if (typeof rule === 'function') {
        if (!rule(item, value)) return false
      } else
        switch (rule) {
          case 'eq': {
            if (String(item[key]) !== String(value)) return false

            break
          }
          case 'includes': {
            if (!stringIncludes(item[key], value)) return false

            break
          }
          case 'fromDate': {
            if (!item[rule.field || 'createdAt']) continue
            if (new Date(item[rule.field || 'createdAt']) < new Date(value)) return false

            break
          }
          // No default
        }
    }
    return true
  })

export const filterDateRange = (items, query, field = 'createdAt') => {
  if (!query.fromDate && !query.toDate) return items
  return items.filter((item) => {
    const v = item[field]
    if (!v) return !query.fromDate && !query.toDate
    const d = new Date(v).getTime()
    if (query.fromDate && d < new Date(query.fromDate).getTime()) return false
    if (query.toDate && d > new Date(query.toDate).getTime()) return false
    return true
  })
}

let nextId = 1000
export const makeId = () => ++nextId

export const findOrThrow = (list, id) => {
  const found = list.find((item) => String(item.id) === String(id))
  if (!found) {
    const err = new Error('Not Found')
    err.response = { status: 404, statusText: 'Not Found', data: { message: 'Not Found' } }
    throw err
  }
  return found
}

export const removeById = (list, id) => {
  const idx = list.findIndex((x) => String(x.id) === String(id))
  if (idx !== -1) list.splice(idx, 1)
}

export const updateById = (list, id, patch) => {
  const idx = list.findIndex((x) => String(x.id) === String(id))
  if (idx === -1) return null
  list[idx] = { ...list[idx], ...patch }
  return list[idx]
}

export const isoDaysFromNow = (days) => new Date(Date.now() + days * 86_400_000).toISOString()

export const isoNow = () => new Date().toISOString()
