import {TUS_VERSION, TUS_RESUMABLE, Metadata} from '@tus/utils'

type validator = (value?: string) => boolean

export const validators = new Map<string, validator>([
  [
    // The Upload-Offset request and response header indicates a byte offset within a resource.
    // The value MUST be a non-negative integer.
    'upload-offset',
    (value) => {
      const n = Number(value)
      return Number.isInteger(n) && String(n) === value && n >= 0
    },
  ],
  [
    // The Upload-Length request and response header indicates the size of the entire upload in bytes.
    // The value MUST be a non-negative integer.
    'upload-length',
    (value) => {
      const n = Number(value)
      return Number.isInteger(n) && String(n) === value && n >= 0
    },
  ],
  [
    // The Upload-Defer-Length request and response header indicates that the size of the upload
    // is not known currently and will be transferred later.
    // Its value MUST be 1. If the length of an upload is not deferred, this header MUST be omitted.
    'upload-defer-length',
    (value) => value === '1',
  ],
  [
    'upload-metadata',
    // The Upload-Metadata request and response header MUST consist of one
    // or more comma-separated key-value pairs. The key and value MUST be
    // separated by a space. The key MUST NOT contain spaces and commas and
    // MUST NOT be empty. The key SHOULD be ASCII encoded and the value MUST
    // be Base64 encoded. All keys MUST be unique.
    (value) => {
      try {
        Metadata.parse(value)
        return true
      } catch {
        return false
      }
    },
  ],
  [
    'x-forwarded-proto',
    (value) => {
      if (value === 'http' || value === 'https') {
        return true
      }
      return false
    },
  ],
  [
    // The Tus-Version response header MUST be a comma-separated list of protocol versions supported by the Server.
    // The list MUST be sorted by Server's preference where the first one is the most preferred one.
    'tus-version',
    (value) => {
      // @ts-expect-error we can compare a literal
      return TUS_VERSION.includes(value)
    },
  ],
  [
    // The Tus-Resumable header MUST be included in every request and response except for OPTIONS requests.
    // The value MUST be the version of the protocol used by the Client or the Server.
    // If the version specified by the Client is not supported by the Server,
    // it MUST respond with the 412 Precondition Failed status and MUST include the Tus-Version header into the response.
    // In addition, the Server MUST NOT process the request.
    'tus-resumable',
    (value) => value === TUS_RESUMABLE,
  ],
  ['content-type', (value) => value === 'application/offset+octet-stream'],
  [
    // The Upload-Concat request and response header MUST be set in both partial and final upload creation requests.
    // It indicates whether the upload is either a partial or final upload.
    // If the upload is a partial one, the header value MUST be partial.
    // In the case of a final upload, its value MUST be final followed by a semicolon and a space-separated list
    // of partial upload URLs that will be concatenated.
    // The partial uploads URLs MAY be absolute or relative and MUST NOT contain spaces as defined in RFC 3986.
    'upload-concat',
    (value) => {
      if (!value) return false
      const valid_partial = value === 'partial'
      const valid_final = value.startsWith('final;')
      return valid_partial || valid_final
    },
  ],
])

export function validateHeader(name: string, value?: string | null): boolean {
  const lowercaseName = name.toLowerCase()
  if (!validators.has(lowercaseName)) {
    return true
  }
  // @ts-expect-error if already guards
  return validators.get(lowercaseName)(value)
}
