// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:convert' hide json;
import 'dart:convert' as convert show json;

import 'package:json_annotation/json_annotation.dart';

/// A converter for tags.
///
/// The JSON format is:
///
/// ```json
/// [
///   {
///     "key": "tag_key",
///     "value": "tag_value"
///   }
/// ]
/// ```
///
/// Which is flattened out as a `Map<String, List<String>>`.
class TagsConverter implements JsonConverter<Map<String?, List<String?>>?, List<dynamic>?> {
  const TagsConverter();

  @override
  Map<String?, List<String?>>? fromJson(List<dynamic>? json) {
    if (json == null) {
      return null;
    }
    final Map<String?, List<String?>> result = <String?, List<String?>>{};
    for (Map<String, dynamic> tag in json.cast<Map<String, dynamic>>()) {
      final String? key = tag['key'] as String?;
      result[key] ??= <String?>[];
      result[key]!.add(tag['value'] as String?);
    }
    return result;
  }

  @override
  List<Map<String, dynamic>>? toJson(Map<String?, List<String?>>? object) {
    if (object == null) {
      return null;
    }
    if (object.isEmpty) {
      return const <Map<String, List<String>>>[];
    }
    final List<Map<String, String>> result = <Map<String, String>>[];
    for (String? key in object.keys) {
      if (key == null) {
        continue;
      }
      final List<String?>? values = object[key];
      if (values == null) {
        continue;
      }
      for (String? value in values) {
        if (value == null) {
          continue;
        }
        result.add(<String, String>{
          'key': key,
          'value': value,
        });
      }
    }
    return result;
  }
}

/// A converter for a "binary" JSON field.
///
/// Encodes and decodes a String to and from base64.
class Base64Converter implements JsonConverter<String, String> {
  const Base64Converter();

  @override
  String fromJson(String json) {
    return utf8.decode(base64.decode(json));
  }

  @override
  String toJson(String object) {
    return base64.encode(utf8.encode(object));
  }
}

/// A converter for "timestamp" fields encoded as microseconds since epoch.
class MicrosecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
  const MicrosecondsSinceEpochConverter();

  @override
  DateTime? fromJson(String? json) {
    if (json == null) {
      return null;
    }
    return DateTime.fromMicrosecondsSinceEpoch(int.parse(json));
  }

  @override
  String? toJson(DateTime? object) {
    if (object == null) {
      return null;
    }
    return object.microsecondsSinceEpoch.toString();
  }
}

/// A converter for "timestamp" fields encoded as milliseconds since epoch.
class MillisecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
  const MillisecondsSinceEpochConverter();

  @override
  DateTime? fromJson(String? json) {
    if (json == null) {
      return null;
    }
    return DateTime.fromMillisecondsSinceEpoch(int.parse(json));
  }

  @override
  String? toJson(DateTime? object) {
    if (object == null) {
      return null;
    }
    return object.millisecondsSinceEpoch.toString();
  }
}

/// A converter for "timestamp" fields encoded as seconds since epoch.
class SecondsSinceEpochConverter implements JsonConverter<DateTime?, String?> {
  const SecondsSinceEpochConverter();

  @override
  DateTime? fromJson(String? json) {
    if (json == null) {
      return null;
    }
    return DateTime.fromMillisecondsSinceEpoch(int.parse(json) * 1000);
  }

  @override
  String? toJson(DateTime? dateTime) {
    if (dateTime == null) {
      return null;
    }
    final int secondsSinceEpoch = dateTime.millisecondsSinceEpoch ~/ 1000;
    return secondsSinceEpoch.toString();
  }
}

/// A converter for boolean fields encoded as strings.
class BoolConverter implements JsonConverter<bool?, String?> {
  const BoolConverter();

  @override
  bool? fromJson(String? json) {
    if (json == null) {
      return null;
    }
    return json.toLowerCase() == 'true';
  }

  @override
  String? toJson(bool? value) {
    if (value == null) {
      return null;
    }
    return '$value';
  }
}

/// A converter for fields with nested JSON objects in String format.
class NestedJsonConverter implements JsonConverter<Map<String, dynamic>?, String?> {
  const NestedJsonConverter();

  @override
  Map<String, dynamic>? fromJson(String? json) {
    if (json == null) {
      return null;
    }
    return convert.json.decode(json) as Map<String, dynamic>?;
  }

  @override
  String? toJson(Map<String, dynamic>? object) {
    if (object == null) {
      return null;
    }
    return convert.json.encode(object);
  }
}
