import { validateProperties, withExtendedStaticProperties } from '../../utils/inheritance.js';
import { maybeFrom, maybeEq } from '../../utils/interfaces.js';
import withBase from './with-base.js';
import withCatchNull from './with-catch-null.js';
import withEq from './with-eq.js';
import '../../utils/types/object.js';
import '../../utils/types/iterable.js';
import '../../utils/types/set.js';
import '../../utils/assert.js';
import '../../utils/error.js';
import '../../utils/types/array.js';
import '../../utils/types/bytes.js';
import 'crypto';
import '../../utils/types/string.js';
import 'bs58';
import 'multiformats/bases/base58';
import 'varint';
import '../../utils/encoding/ss-58.js';
import 'blake2b';
import './with-from-json-bytes.js';
import './any-of.js';
import './with-from.js';

class TypedStruct extends withBase(class StructBase {}) {
  static Classes;

  constructor(...values) {
    super();

    let idx = 0;
    for (const key of Object.keys(this.constructor.Classes)) {
      const prop = Symbol(key);

      Object.defineProperty(this, key, {
        enumerable: true,
        get() {
          return this[prop];
        },
        set(newValue) {
          try {
            this[prop] = maybeFrom(this.constructor.Classes[key], newValue);
          } catch (error) {
            error.message = `\nFailed to set property \`${key}\` of \`${this.constructor.name}\`: ${error.message}`;

            throw error;
          }
        },
      });

      this[key] = values[idx++];
    }

    validateProperties(this);
    Object.seal(this);
  }

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

  static fromJSON(obj) {
    return new this(...Object.keys(this.Classes).map((key) => obj[key]));
  }

  static fromApi(obj) {
    return this.fromJSON(obj);
  }

  eq(other) {
    const thisEntries = Object.entries(this);
    const otherEntries = Object.entries(other);

    if (thisEntries.length !== otherEntries.length) {
      return false;
    }

    for (const key of Object.keys(this)) {
      if (!maybeEq(this[key], other[key])) {
        return false;
      }
    }

    return true;
  }

  toString() {
    return JSON.stringify(this.toJSON());
  }

  toJSON() {
    const result = {};
    for (const key of Object.keys(this)) {
      const value = this[key];
      result[key] = value && typeof value.toJSON === 'function' ? value.toJSON() : value;
    }
    return result;
  }
}

var TypedStruct$1 = withEq(
  withCatchNull(withExtendedStaticProperties(['Classes'], TypedStruct)),
);

export { TypedStruct$1 as default };
//# sourceMappingURL=typed-struct.js.map
