import { escapeRegExp } from 'lodash-es'

export const createPageUrl = (
  page: number,
  currentUrl: URL | string,
  otherParams?: Record<string, string | null | undefined> | URLSearchParams
) => {
  const url = new URL(currentUrl)
  if (otherParams) {
    if (otherParams instanceof URLSearchParams) {
      otherParams.forEach((value, key) => {
        url.searchParams.set(key, value)
      })
    } else {
      Object.entries(otherParams).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
          url.searchParams.set(key, value)
        }
      })
    }
  }
  url.searchParams.set('page', page.toString())

  return url.toString()
}

export function urlParamsToFormData(params: URLSearchParams) {
  const formData = new FormData()
  params.forEach((value, key) => {
    formData.append(key, value)
  })
  return formData
}

export function urlParamsToObject(params: URLSearchParams) {
  return Object.fromEntries(params.entries())
}

export function urlWithParams(
  url: URL | string,
  params: Record<string, number[] | string[] | number | string | null | undefined>,
  { clearExisting }: { clearExisting?: boolean } = { clearExisting: false }
) {
  const urlObj = new URL(url)
  if (clearExisting) {
    const keysToDelete = Array.from(urlObj.searchParams.keys())
    keysToDelete.forEach((key) => {
      urlObj.searchParams.delete(key)
    })
  }
  Object.entries(params).forEach(([key, value]) => {
    if (Array.isArray(value)) {
      value.forEach((v) => {
        urlObj.searchParams.append(key, String(v))
      })
    } else if (value === null || value === undefined) {
      urlObj.searchParams.delete(key)
    } else {
      urlObj.searchParams.set(key, String(value))
    }
  })
  return urlObj.toString()
}

export function makeObjectSearchParamKeyRegex(key: string) {
  return new RegExp(`^${escapeRegExp(key)}-(.*)$`)
}

/**
 * Parses the value of an object from a URL with zod. Assuming this format: `key[subkey]=value`
 *
 * Returns an object with the keys as the subkeys and the values as the values.
 * Or `undefined` if there are no subkeys.
 *
 * If there is no subkey (`key=value`), the subkey is set to an empty string.
 *
 * @example
 * ```ts
 * const searchParams = new URLSearchParams('tag-en=include&tag-fr=exclude&tag-es=')
 * const value = getObjectSearchParam(searchParams, 'tag')
 * // value: { en: 'include', fr: 'exclude'}
 * ```
 */
export function getObjectSearchParam(
  params: URLSearchParams,
  key: string,
  {
    ignoreEmptyValues = true,
    emptyObjectBecomesUndefined = true,
  }: {
    ignoreEmptyValues?: boolean
    emptyObjectBecomesUndefined?: boolean
  } = {}
) {
  const keyPattern = makeObjectSearchParamKeyRegex(key)

  const entries = Array.from(params.entries()).flatMap(([paramKey, paramValue]) => {
    if (ignoreEmptyValues && paramValue === '') return []
    if (paramKey === key) return [['', paramValue]] as const

    const subKey = paramKey.match(keyPattern)?.[1]
    if (subKey === undefined) return []
    return [[subKey, paramValue]] as const
  })

  if (entries.length === 0) return emptyObjectBecomesUndefined ? undefined : {}
  return Object.fromEntries(entries)
}

export function urlDomain(url: URL | string) {
  if (typeof url === 'string') {
    return url.replace(/^(https?:\/\/)?(www\.)?/, '').replace(/\/(index\.html)?$/, '')
  }
  return url.origin
}
