import { DidMethodKeySignature, DidMethodKeyPublicKey } from './did-method-key/did-method-key-public-key.js';
import './did-method-key/did-method-key-signature.js';
import DockDidValue, { DockDidSignature } from './dock-did-value.js';
import TypedEnum from '../../../generic/typed-enum.js';
import '../../../generic/typed-bytes.js';
import '../../../generic/typed-string.js';
import '../../../generic/typed-array.js';
import TypedTuple from '../../../generic/typed-tuple.js';
import '../../../generic/typed-null.js';
import '../../../../utils/types/array.js';
import { isHexWithGivenByteSize } from '../../../../utils/types/bytes.js';
import { withExtendedStaticProperties } from '../../../../utils/inheritance.js';
import 'bs58';
import 'multiformats/bases/base58';
import 'varint';
import '../../../../utils/encoding/ss-58.js';
import '../../../generic/typed-number.js';
import '../../../generic/typed-set.js';
import '../../../generic/typed-map.js';
import '../../../generic/typed-struct.js';
import TypedUUID from '../../../generic/typed-uuid.js';
import withQualifier from '../../../generic/with-qualifier.js';
import { createConverter } from '../../../generic/utils.js';
import { CheqdTestnetDid, CheqdMainnetDid, CheqdDid } from './cheqd-did.js';
export { CheqdDLRRef, CheqdDidValue, CheqdMainnetDidValue, CheqdTestnetDidValue } from './cheqd-did.js';
import DidOrDidMethodKeySignature from './signature.js';
import '../../../../utils/encoding/base-58-btc.js';
import '../../../../utils/types/string.js';
import '../../../../utils/error.js';
import '../../../generic/sized.js';
import '../../../../utils/types/number.js';
import 'crypto';
import 'uuid';
import 'js-sha256';
import '../../../public-keys/public-key.js';
import '../../../public-keys/public-key-x25519-value.js';
import '../../../public-keys/public-key-ed25519-value.js';
import '../../../../vc/crypto/constants.js';
import '../../../public-keys/public-key-secp256k1-value.js';
import '../../../public-keys/public-key-sr25519-value.js';
import '../constants.js';
import '../../../signatures/signature-value.js';
import '../../../signatures/signature-ed25519-value.js';
import '../../../signatures/signature-secp256k1-value.js';
import '../../../signatures/signature.js';
import '../../../signatures/signature-sr25519-value.js';
import '../../../../utils/types/iterable.js';
import '../../../../utils/types/object.js';
import '../../../../utils/interfaces.js';
import '../../../../utils/assert.js';
import '../../../generic/with-base.js';
import '../../../generic/with-catch-null.js';
import '../../../generic/with-eq.js';
import '../../../generic/any-of.js';
import '../../../generic/with-from.js';
import '../../../generic/with-from-json-bytes.js';
import '../../../generic/create-placeholder.js';
import '../../../../utils/types/set.js';
import 'blake2b';
import '../../../generic/typed-bytes-array.js';

class DockDidOrDidMethodKey extends withQualifier(TypedEnum, true) {
  /**
   * Instantiates a random `dock:did:*`.
   */
  static random() {
    return new this(this.Class.random());
  }

  signWith(keyPair, bytes) {
    return this.value.signWith(keyPair, bytes);
  }

  /**
   * Creates signature for the state change with supplied arguments.
   *
   * @param apiProvider
   * @param name
   * @param payload
   * @param keyRef
   * @returns {object}
   */
  async signStateChange(apiProvider, name, payload, keyRef) {
    const { LOG_STATE_CHANGE } = process.env;
    if (Number(LOG_STATE_CHANGE) || Boolean(LOG_STATE_CHANGE)) {
      console.dir(payload, { depth: null });
    }
    const bytes = await apiProvider.stateChangeBytes(name, payload);

    return this.signWith(keyRef, bytes);
  }

  /**
   * Creates a transaction that will modify the chain state.
   *
   * @param api
   * @param method
   * @param name
   * @param payload
   * @param keyRef
   */
  async changeState(api, method, name, payload, keyRef) {
    return await method(
      payload,
      await this.signStateChange(api, name, payload, keyRef),
    );
  }

  toString() {
    return String(this.value);
  }

  static fromApi(value) {
    if (value.isDock) {
      return super.from(value.asDock);
    } else {
      return super.fromApi(value);
    }
  }

  static fromJSON(json) {
    if (json?.dock) {
      return super.fromJSON({ did: json?.dock });
    } else {
      return super.fromJSON(json);
    }
  }

  static from(value) {
    if (isHexWithGivenByteSize(String(value), 32)) {
      // eslint-disable-next-line no-use-before-define
      return new DockDid(value);
    }

    // eslint-disable-next-line no-use-before-define
    if (value instanceof NamespaceDid) {
      return super.from(value.isDock ? { did: value.asDock } : value);
    } else {
      return super.from(value);
    }
  }
}

class DockDid extends DockDidOrDidMethodKey {
  static Class = DockDidValue;

  toHex() {
    return this.value.toHex();
  }

  toQualifiedString() {
    return this.value.toQualifiedString();
  }
}

class DidMethodKey extends DockDidOrDidMethodKey {
  static Class = DidMethodKeyPublicKey;

  static fromKeypair(keypair) {
    return new this(DidMethodKeyPublicKey.fromKeypair(keypair));
  }
}

DockDidOrDidMethodKey.bindVariants(DockDid, DidMethodKey);

class NamespaceDid extends withQualifier(TypedEnum, true) {
  toCheqdPayload() {
    return String(this);
  }

  toJSON() {
    return String(this);
  }

  static fromApi(value) {
    if (value.isDid) {
      return super.from({ dock: value.asDid });
    } else {
      return super.fromApi(value);
    }
  }

  static fromJSON(json) {
    if (json?.did && Object.keys(json).length === 1) {
      return super.fromJSON({ dock: json.did });
    } else {
      return super.fromJSON(json);
    }
  }

  static from(value) {
    return super.from(
      value instanceof DockDidOrDidMethodKey && value.isDid
        ? { dock: value.asDid }
        : value,
    );
  }
}

class DockNamespaceDid extends NamespaceDid {
  static Qualifier = 'did:dock:';

  static Type = 'dock';

  static Class = DockDidValue;
}
class DidNamespaceKey extends NamespaceDid {
  static Qualifier = 'did:key:';

  static Type = 'didMethodKey';

  static Class = DidMethodKeyPublicKey;
}
class CheqdNamespaceDid extends NamespaceDid {
  static Qualifier = 'did:cheqd:';

  static Type = 'cheqd';

  static Class = CheqdDid;
}

NamespaceDid.bindVariants(DockNamespaceDid, DidNamespaceKey, CheqdNamespaceDid);

for (const Class of [CheqdTestnetDid, CheqdMainnetDid]) {
  const fromFn = Class.from;

  Class.from = function from(value) {
    try {
      return new this(
        TypedUUID.fromDockIdent(DockNamespaceDid.from(value), 'did:cheqd:'),
      );
    } catch {
      return fromFn.call(this, value);
    }
  };
}

class DidRef extends withExtendedStaticProperties(
  ['Ident'],
  withQualifier(TypedTuple),
) {
  static Qualifier = '';

  static Did = NamespaceDid;

  static get Classes() {
    return [this.Did, this.Ident];
  }

  static random(did) {
    return new this(did, this.Ident.random());
  }

  get did() {
    return this[0];
  }

  get value() {
    return this[1];
  }

  static fromUnqualifiedString(str) {
    const regex = new RegExp(`^${this.Qualifier}([^#]+):(.+)$`);
    const match = str.match(regex);

    if (!match) {
      throw new Error(`Invalid format for DID reference: \`${str}\``);
    }

    const [, did, value] = match;
    return new this(did, value);
  }

  toEncodedString() {
    const { did, value } = this;

    return `${did}:${value}`;
  }

  toJSON() {
    return String(this);
  }
}

class CheqdDidRef extends withQualifier(DidRef) {
  static Did = CheqdDid;

  static fromUnqualifiedString(str) {
    const lastColon = str.lastIndexOf(':');
    const did = `did:cheqd:${str.slice(0, lastColon)}`;
    const id = str.slice(lastColon + 1);

    return new this(did, id);
  }

  toJSON() {
    return String(this);
  }

  toEncodedString() {
    const { did, value } = this;

    let prefix = '';
    if (did.isTestnet) {
      prefix = 'testnet';
    } else if (did.isMainnet) {
      prefix = 'mainnet';
    } else {
      throw new Error(
        `Can't determine DID type: \`${did}\`, instance of \`${did.constructor.name}\``,
      );
    }

    return `${prefix}:${did.toEncodedString()}:${value}`;
  }
}

DidOrDidMethodKeySignature.bindVariants(
  DockDidSignature,
  DidMethodKeySignature,
);

/**
 * Retrieve all possible stringified representations of DIDs that can be derived from the provided Dock DID.
 *
 * @param {*} did
 * @returns {Array<string>}
 */
const possibleDids = createConverter(
  String,
  DockDid,
  CheqdTestnetDid,
  CheqdMainnetDid,
);

export { CheqdDid, CheqdDidRef, CheqdMainnetDid, CheqdNamespaceDid, CheqdTestnetDid, DidMethodKey, DidMethodKeyPublicKey, DidNamespaceKey, DidRef, DockDid, DockDidOrDidMethodKey, DockDidValue, DockNamespaceDid, NamespaceDid, possibleDids };
//# sourceMappingURL=index.js.map
