/* eslint-disable @rushstack/typedef-var */
import { EpochOrFromNow, ICookieOptions, TimeString } from '@iopa/types'

const mins = ['m', 'min', 'mins', 'minute', 'minutes']
const hrs = ['h', 'hr', 'hrs', 'hour', 'hours']
const days = ['d', 'day', 'days']
const weeks = ['w', 'wk', 'wks', 'week', 'weeks']
const timeUnits: string[][] = [mins, hrs, days, weeks]

export function getSeconds(timeString: TimeString): number {
  const [val, unit] = timeString.split(' ')
  const time = Number.parseInt(val, 10)
  if (Number.isNaN(time)) {
    return 0
  }
  const multipliers: number[] = [60, 3600, 86400, 604800]
  for (let i = 0; i < timeUnits.length; i++) {
    if (timeUnits[i].includes(unit)) {
      return time * multipliers[i]
    }
  }
  return 0
}

function getMaxAge(age: TimeString): string {
  return `Max-Age=${getSeconds(age)}`
}

function getExpires(date: EpochOrFromNow): string {
  if (typeof date === 'number') {
    return `Expires=${new Date(date).toUTCString()}`
  }
  return `Expires=${new Date(
    Date.now() + getSeconds(date) * 1000
  ).toUTCString()}`
}

function mapOptionsToString({
  options
}: {
  options: {
    expires?: EpochOrFromNow
    maxAge?: TimeString
    domain?: string
    path?: string
    secure?: boolean
    httpOnly?: boolean
    sameSite?: 'Strict' | 'Lax' | 'None'
  }
}): string {
  const { expires, maxAge, domain, path, secure, httpOnly, sameSite } = options
  let opt = ''
  if (expires) {
    opt += ` ${getExpires(expires)};`
  }
  if (maxAge) {
    opt += ` ${getMaxAge(maxAge)};`
  }
  if (domain) {
    opt += ` Domain=${domain};`
  }
  if (path) {
    opt += ` Path=${path};`
  }
  if (secure) {
    opt += ' Secure;'
  }
  if (httpOnly) {
    opt += ' HttpOnly;'
  }
  if (sameSite) {
    opt += ` SameSite=${sameSite};`
  }
  return opt
}

// mapOptionsToString({ httpOnly: true, secure: true, sameSite: 'Lax', maxAge: '7 days', expires: '52 wk', path: '/auth', domain: 'site.com' });
// ' Expires=Tue, 20 Jan 1970 00:54:53 GMT; Max-Age=604800; Domain=site.com; Path=/auth; Secure; HttpOnly; SameSite=Lax;';

export default {
  set: (
    headers: Headers,
    name: string,
    value: string,
    options?: ICookieOptions
  ) => {
    let cookie = `${name}=${value};`
    if (options) {
      cookie += mapOptionsToString({ options })
    }
    headers.append('set-cookie', cookie)
  },
  clear: (
    headers: Headers,
    name: string,
    options?: Pick<ICookieOptions, 'domain' | 'path'>
  ) => {
    let cookie = `${name}=; ${getExpires(0)};`
    if (options) {
      cookie += mapOptionsToString({ options })
    }
    headers.append('set-cookie', cookie)
  }
}
