/*
 * Copyright 2021 Juan Cruz Viotti
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  strict as assert
} from 'assert'

import ResizableBuffer from '../resizable-buffer'

import {
  SchemasOptions
} from './options'

import {
  EncodingContext
} from '../context'

import {
  JSONValue
} from '../../json'

import {
  validateSchema
} from '../../schema'

import {
  FLOOR_MULTIPLE_ENUM_VARINT
} from '../integer/encode'

import {
  encode
} from '../index'

export const ONEOF_CHOICE_INDEX_PREFIX = (
  buffer: ResizableBuffer, offset: number, value: JSONValue,
  options: SchemasOptions, context: EncodingContext
): number => {
  assert(options.choices.length > 0)

  // Find which of the choices is the one that applies
  let choiceIndex: number = -1
  for (const [ index, definition ] of options.choices.entries()) {
    // TODO: By no means we should be doing full-blown JSON Schema validation
    // here. We should instead be compiling the schema into something simpler
    // that we can check and use that intead.
    if (validateSchema(definition.schema, value)) {
      choiceIndex = index
      break
    }
  }
  assert(choiceIndex >= 0)

  // Record which of the choices was used
  const indexBytes: number = FLOOR_MULTIPLE_ENUM_VARINT(buffer, offset, choiceIndex, {
    minimum: 0,
    multiplier: 1
  }, context)

  // Proceed with encoding against the given choice
  const bytesWritten: number =
    encode(buffer, offset + indexBytes,
      options.choices[choiceIndex].encoding, value, context)
  return indexBytes + bytesWritten
}
