// Copyright (c) 2014, 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.

part of '../../db.dart';

/// Annotation used to mark dart classes which can be stored into datastore.
///
/// The `Kind` annotation on a class as well as other `Property` annotations on
/// fields or getters of the class itself (and any of it's superclasses) up to
/// the [Model] class describe the *mapping* of *dart objects* to datastore
/// *entities*.
///
/// An "entity" is an object which can be stored into Google Cloud Datastore.
/// It contains a number of named "properties", some of them might get indexed,
/// others are not. A "property" value can be of a limited set of supported
/// types (such as `int` and `String`).
///
/// Here is an example of a dart model class which can be stored into datastore:
///     @Kind()
///     class Person extends db.Model {
///       @StringProperty()
///       String name;
///
///       @IntProperty()
///       int age;
///
///       @DateTimeProperty()
///       DateTime dateOfBirth;
///     }
class Kind {
  /// The kind name used when saving objects to datastore.
  ///
  /// If `null` the name will be the same as the class name at which the
  /// annotation is placed.
  final String? name;

  /// The type, either [ID_TYPE_INTEGER] or [ID_TYPE_STRING].
  final IdType idType;

  /// Annotation specifying the name of this kind and whether to use integer or
  /// string `id`s.
  ///
  /// If `name` is omitted, it will default to the name of class to which this
  /// annotation is attached to.
  const Kind({this.name, this.idType = IdType.Integer});
}

/// The type used for id's of an entity.
class IdType {
  /// Use integer ids for identifying entities.
  // ignore: constant_identifier_names
  static const IdType Integer = IdType('Integer');

  /// Use string ids for identifying entities.
  // ignore: constant_identifier_names
  static const IdType String = IdType('String');

  final core.String _type;

  const IdType(this._type);

  @override
  core.String toString() => 'IdType: $_type';
}

/// Describes a property of an Entity.
///
/// Please see [Kind] for an example on how to use them.
abstract class Property {
  /// The name of the property.
  ///
  /// If it is `null`, the name will be the same as used in the
  /// model class.
  final String? propertyName;

  /// Specifies whether this property is required or not.
  ///
  /// If required is `true`, it will be enforced when saving model objects to
  /// the datastore and when retrieving them.
  final bool required;

  /// Specifies whether this property should be indexed or not.
  ///
  /// When running queries no this property, it is necessary to set [indexed] to
  /// `true`.
  final bool indexed;

  const Property(
      {this.propertyName, this.required = false, this.indexed = true});

  bool validate(ModelDB db, Object? value) {
    if (required && value == null) return false;
    return true;
  }

  Object? encodeValue(ModelDB db, Object? value, {bool forComparison = false});

  Object? decodePrimitiveValue(ModelDB db, Object? value);
}

/// An abstract base class for primitive properties which can e.g. be used
/// within a composed `ListProperty`.
abstract class PrimitiveProperty extends Property {
  const PrimitiveProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  Object? encodeValue(ModelDB db, Object? value,
          {bool forComparison = false}) =>
      value;

  @override
  Object? decodePrimitiveValue(ModelDB db, Object? value) => value;
}

/// A boolean [Property].
///
/// It will validate that values are booleans before writing them to the
/// datastore and when reading them back.
class BoolProperty extends PrimitiveProperty {
  const BoolProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is bool);
}

/// A integer [Property].
///
/// It will validate that values are integers before writing them to the
/// datastore and when reading them back.
class IntProperty extends PrimitiveProperty {
  const IntProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is int);
}

/// A double [Property].
///
/// It will validate that values are doubles before writing them to the
/// datastore and when reading them back.
class DoubleProperty extends PrimitiveProperty {
  const DoubleProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is double);
}

/// A string [Property].
///
/// It will validate that values are strings before writing them to the
/// datastore and when reading them back.
class StringProperty extends PrimitiveProperty {
  const StringProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is String);
}

/// A key [Property].
///
/// It will validate that values are keys before writing them to the
/// datastore and when reading them back.
class ModelKeyProperty extends PrimitiveProperty {
  const ModelKeyProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is Key);

  @override
  Object? encodeValue(ModelDB db, Object? value, {bool forComparison = false}) {
    if (value == null) return null;
    return db.toDatastoreKey(value as Key);
  }

  @override
  Object? decodePrimitiveValue(ModelDB db, Object? value) {
    if (value == null) return null;
    return db.fromDatastoreKey(value as ds.Key);
  }
}

/// A binary blob [Property].
///
/// It will validate that values are blobs before writing them to the
/// datastore and when reading them back. Blob values will be represented by
/// List<int>.
class BlobProperty extends PrimitiveProperty {
  const BlobProperty({String? propertyName, bool required = false})
      : super(propertyName: propertyName, required: required, indexed: false);

  // NOTE: We don't validate that the entries of the list are really integers
  // of the range 0..255!
  // If an untyped list was created the type check will always succeed. i.e.
  //   "[1, true, 'bar'] is List<int>" evaluates to `true`
  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is List<int>);

  @override
  Object? encodeValue(ModelDB db, Object? value, {bool forComparison = false}) {
    if (value == null) return null;
    return ds.BlobValue(value as List<int>);
  }

  @override
  Object? decodePrimitiveValue(ModelDB db, Object? value) {
    if (value == null) return null;

    return (value as ds.BlobValue).bytes;
  }
}

/// A datetime [Property].
///
/// It will validate that values are DateTime objects before writing them to the
/// datastore and when reading them back.
class DateTimeProperty extends PrimitiveProperty {
  const DateTimeProperty(
      {String? propertyName, bool required = false, bool indexed = true})
      : super(propertyName: propertyName, required: required, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) =>
      super.validate(db, value) && (value == null || value is DateTime);

  @override
  Object? decodePrimitiveValue(ModelDB db, Object? value) {
    if (value is int) {
      return DateTime.fromMillisecondsSinceEpoch(value ~/ 1000, isUtc: true);
    }
    return value;
  }
}

/// A composed list [Property], with a `subProperty` for the list elements.
///
/// It will validate that values are List objects before writing them to the
/// datastore and when reading them back. It will also validate the elements
/// of the list itself.
class ListProperty extends Property {
  final PrimitiveProperty subProperty;

  // TODO: We want to support optional list properties as well.
  // Get rid of "required: true" here.
  const ListProperty(this.subProperty,
      {String? propertyName, bool indexed = true})
      : super(propertyName: propertyName, required: true, indexed: indexed);

  @override
  bool validate(ModelDB db, Object? value) {
    if (!super.validate(db, value) || value is! List) return false;

    for (var entry in value) {
      if (!subProperty.validate(db, entry)) return false;
    }
    return true;
  }

  @override
  Object? encodeValue(ModelDB db, Object? value, {bool forComparison = false}) {
    if (forComparison) {
      // If we have comparison of list properties (i.e. repeated property names)
      // the comparison object must not be a list, but the value itself.
      // i.e.
      //
      //   class Article {
      //      ...
      //      @ListProperty(StringProperty())
      //      List<String> tags;
      //      ...
      //   }
      //
      // should be queried via
      //
      //   await db.query(Article, 'tags=', "Dart").toList();
      //
      // So the [value] for the comparison is of type `String` and not
      // `List<String>`!
      return subProperty.encodeValue(db, value, forComparison: true);
    }

    if (value == null) return null;
    var list = value as List;
    if (list.isEmpty) return null;
    if (list.length == 1) return subProperty.encodeValue(db, list[0]);
    return list.map((value) => subProperty.encodeValue(db, value)).toList();
  }

  @override
  Object decodePrimitiveValue(ModelDB db, Object? value) {
    if (value == null) return [];
    if (value is! List) return [subProperty.decodePrimitiveValue(db, value)];
    return value
        .map((entry) => subProperty.decodePrimitiveValue(db, entry))
        .toList();
  }
}

/// A convenience [Property] for list of strings.
class StringListProperty extends ListProperty {
  const StringListProperty({String? propertyName, bool indexed = true})
      : super(const StringProperty(),
            propertyName: propertyName, indexed: indexed);

  @override
  Object decodePrimitiveValue(ModelDB db, Object? value) {
    return (super.decodePrimitiveValue(db, value) as core.List).cast<String>();
  }
}
