// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'json_key.dart';

/// Returns the key associated with value [source] from [enumValues], if one
/// exists.
///
/// If [unknownValue] is not `null` and [source] is not a value in [enumValues],
/// [unknownValue] is returned. Otherwise, an [ArgumentError] is thrown.
///
/// If [source] is `null`, `null` is returned.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
K? $enumDecodeNullable<K extends Enum, V>(
  Map<K, V> enumValues,
  Object? source, {
  Enum? unknownValue,
}) {
  if (source == null) {
    return null;
  }

  for (var entry in enumValues.entries) {
    if (entry.value == source) {
      return entry.key;
    }
  }

  if (unknownValue == JsonKey.nullForUndefinedEnumValue) {
    return null;
  }

  if (unknownValue == null) {
    throw ArgumentError(
      '`$source` is not one of the supported values: '
      '${enumValues.values.join(', ')}',
    );
  }

  if (unknownValue is! K) {
    throw ArgumentError.value(
      unknownValue,
      'unknownValue',
      'Must by of type `$K` or `JsonKey.nullForUndefinedEnumValue`.',
    );
  }

  return unknownValue;
}

/// Returns the key associated with value [source] from [enumValues], if one
/// exists.
///
/// If [unknownValue] is not `null` and [source] is not a value in [enumValues],
/// [unknownValue] is returned. Otherwise, an [ArgumentError] is thrown.
///
/// If [source] is `null`, an [ArgumentError] is thrown.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
K $enumDecode<K extends Enum, V>(
  Map<K, V> enumValues,
  Object? source, {
  K? unknownValue,
}) {
  if (source == null) {
    throw ArgumentError(
      'A value must be provided. Supported values: '
      '${enumValues.values.join(', ')}',
    );
  }

  for (var entry in enumValues.entries) {
    if (entry.value == source) {
      return entry.key;
    }
  }

  if (unknownValue == null) {
    throw ArgumentError(
      '`$source` is not one of the supported values: '
      '${enumValues.values.join(', ')}',
    );
  }

  return unknownValue;
}
