'use strict';

var utils_interfaces = require('../../utils/interfaces.cjs');
var utils_inheritance = require('../../utils/inheritance.cjs');
var types_generic_withBase = require('./with-base.cjs');
var types_generic_withCatchNull = require('./with-catch-null.cjs');
var types_generic_withEq = require('./with-eq.cjs');
require('../../utils/assert.cjs');
require('../../utils/error.cjs');
require('../../utils/types/object.cjs');
require('../../utils/types/iterable.cjs');
require('../../utils/types/set.cjs');
require('../../utils/types/array.cjs');
require('../../utils/types/bytes.cjs');
require('crypto');
require('../../utils/types/string.cjs');
require('bs58');
require('multiformats/bases/base58');
require('varint');
require('../../utils/encoding/ss-58.cjs');
require('blake2b');
require('./with-from-json-bytes.cjs');
require('./any-of.cjs');
require('./with-from.cjs');

let TypedMap$1 = class TypedMap extends types_generic_withBase(Map) {
  static KeyClass;

  static ValueClass;

  constructor(values = []) {
    super();

    this.keysAsKeyClass = new Map();

    for (const [key, value] of values) {
      this.set(key, value);
    }
  }

  keyAsKeyClass(key) {
    const asKeyClass = utils_interfaces.maybeFrom(this.constructor.KeyClass, key);
    const strKey = utils_interfaces.maybeToJSONString(asKeyClass);

    if (this.keysAsKeyClass.has(strKey)) {
      return this.keysAsKeyClass.get(strKey);
    } else {
      this.keysAsKeyClass.set(strKey, asKeyClass);

      return asKeyClass;
    }
  }

  set(key, value) {
    return super.set(
      this.keyAsKeyClass(key),
      utils_interfaces.maybeFrom(this.constructor.ValueClass, value),
    );
  }

  get(key) {
    return super.get(this.keyAsKeyClass(key));
  }

  has(key) {
    return super.has(this.keyAsKeyClass(key));
  }

  delete(key) {
    const removed = super.delete(this.keyAsKeyClass(key));
    if (removed) this.keysAsKeyClass.delete(key);

    return removed;
  }

  clear() {
    this.clear();
    this.keysAsKeyClass.clear();
  }

  toJSON() {
    return this.apply(utils_interfaces.maybeToJSON).sort(([k1], [k2]) => String(k1).localeCompare(String(k2)));
  }

  apply(fn) {
    return [...this.entries()].map(([key, value]) => [fn(key), fn(value)]);
  }

  static fromJSON(entries) {
    return new this(
      [...entries].map(([key, value]) => [
        this.KeyClass.fromJSON(key),
        this.ValueClass.fromJSON(value),
      ]),
    );
  }

  static fromApi(obj) {
    return new this(
      [...obj.entries()].map(([key, value]) => [
        this.KeyClass.fromApi(key),
        this.ValueClass.fromApi(value),
      ]),
    );
  }

  static from(obj) {
    if (obj instanceof this) {
      return obj;
    } else if (Array.isArray(obj)) {
      return this.fromJSON(obj);
    } else if (obj && typeof obj === 'object') {
      return this.fromApi(obj);
    } else {
      return new this(obj);
    }
  }

  eq(other) {
    return (
      this.size === other.size
      && this.entries().all(([key, value]) => utils_interfaces.maybeEq(other.get(key), value))
    );
  }

  diff(other) {
    return {
      added: new this.constructor(
        [...this.keys()]
          .filter((key) => !other.has(key))
          .map((key) => [key, this.get(key)]),
      ),
      removed: new this.constructor(
        [...other.keys()]
          .filter((key) => !this.has(key))
          .map((key) => [key, other.get(key)]),
      ),
      modified: new this.constructor(
        [...this.keys()]
          .filter((key) => other.has(key) && !this.get(key).eq(other.get(key)))
          .map((key) => [key, this.get(key)]),
      ),
    };
  }
};

var TypedMap = types_generic_withEq(
  types_generic_withCatchNull(
    utils_inheritance.withExtendedStaticProperties(['KeyClass', 'ValueClass'], TypedMap$1),
  ),
);

module.exports = TypedMap;
//# sourceMappingURL=typed-map.cjs.map
