import '../../generic/typed-enum.js';
import '../../generic/typed-bytes.js';
import TypedString from '../../generic/typed-string.js';
import TypedArray from '../../generic/typed-array.js';
import '../../generic/typed-tuple.js';
import '../../generic/typed-null.js';
import option from '../../generic/option.js';
import '../../../utils/types/array.js';
import 'crypto';
import { ensureEqualToOrPrototypeOf } from '../../../utils/inheritance.js';
import 'bs58';
import 'multiformats/bases/base58';
import 'varint';
import '../../../utils/encoding/ss-58.js';
import TypedNumber from '../../generic/typed-number.js';
import TypedSet from '../../generic/typed-set.js';
import '../../generic/typed-map.js';
import TypedStruct from '../../generic/typed-struct.js';
import TypedUUID from '../../generic/typed-uuid.js';
import withFrom from '../../generic/with-from.js';
import { NamespaceDid, CheqdNamespaceDid } from '../onchain/typed-did/index.js';
import { DidKey, DidKeys } from '../onchain/did-key.js';
import { VerificationRelationship } from '../onchain/verification-relationship.js';
import { Service, createServiceEndpoint, ServiceEndpointId, DIDCommService, CheqdService, CheqdTestnetService, CheqdMainnetService } from './service-endpoint.js';
export { CheqdMainnetServiceEndpointId, CheqdServiceEndpointId, CheqdTestnetServiceEndpointId, DIDCommMessaging, DIDCommServiceEndpoint, DIDCommServiceEndpointValue, DIDCommServiceEndpoints, DIDCommServiceEndpointsArray, LinkedDomains, ServiceEndpoint, ServiceEndpointOrigin, ServiceEndpointOrigins, ServiceEndpointType, ServiceEndpointValue, ServiceEndpoints, ServiceEndpointsType, SuffixServiceEndpointId, UnknownServiceEndpoint } from './service-endpoint.js';
import { VerificationMethod, CheqdVerificationMethod, CheqdTestnetVerificationMethod, CheqdMainnetVerificationMethod } from './verification-method.js';
export { CheqdMainnetPublicKeyMetadata, CheqdMainnetVerificationMethodAssertion, CheqdMainnetVerificationMethodAssertionLegacy, CheqdPublicKeyMetadata, CheqdTestnetPublicKeyMetadata, CheqdTestnetVerificationMethodAssertion, CheqdTestnetVerificationMethodAssertionLegacy, CheqdVerificationMethodAssertion, CheqdVerificationMethodAssertionLegacy, DockPublicKeyMetadata, PublicKeyBase58, PublicKeyBase58OrMultibase, PublicKeyBase64, PublicKeyMetadata, PublicKeyMultibase, TypedJsonWebKey } from './verification-method.js';
import { CheqdVerificationMethodRefOrCheqdVerificationMethod, CheqdTestnetVerificationMethodOrCheqdTestnetVerificationMethodRef, CheqdMainnetVerificationMethodOrCheqdMainnetVerificationMethodRef } from './verification-method-ref-or-cheqd-verification-method.js';
import { VerificationMethodRef, CheqdVerificationMethodRef, CheqdTestnetVerificationMethodRef, CheqdMainnetVerificationMethodRef } from './verification-method-ref.js';
import { ATTESTS_IRI, CONTEXT_URI } from './const.js';
export { Bls12381BBDT16VerificationKeyDock2024, Bls12381BBSVerificationKeyDock2023, Bls12381G2VerificationKeyDock2022, Bls12381PSVerificationKeyDock2023, EcdsaSecp256k1VerificationKey2019, Ed25519Verification2018Method, Ed25519Verification2020Method, JsonWebKey2020Method, Sr25519Verification2020Method, VerificationMethodType, X25519KeyAgreementKey2019 } from './verification-method-type.js';
export { default as IdentRef } from './ident-ref.js';
import { CheqdTestnetDid, CheqdMainnetDid } from '../onchain/typed-did/cheqd-did.js';
import '../../../utils/types/iterable.js';
import '../../../utils/types/object.js';
import '../../../utils/interfaces.js';
import '../../../utils/assert.js';
import '../../../utils/error.js';
import '../../generic/with-base.js';
import '../../../utils/types/bytes.js';
import '../../../utils/types/string.js';
import '../../../utils/types/set.js';
import '../../generic/with-catch-null.js';
import '../../generic/with-eq.js';
import '../../generic/any-of.js';
import 'blake2b';
import '../../generic/with-from-json-bytes.js';
import '../../generic/create-placeholder.js';
import 'uuid';
import 'js-sha256';
import '../onchain/typed-did/did-method-key/did-method-key-public-key.js';
import '../../../utils/encoding/base-58-btc.js';
import '../../generic/sized.js';
import '../../../utils/types/number.js';
import '../../generic/with-qualifier.js';
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 '../onchain/constants.js';
import '../onchain/typed-did/signature.js';
import '../onchain/typed-did/did-method-key/did-method-key-signature.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 '../onchain/typed-did/dock-did-value.js';
import '../../generic/utils.js';
import '../../generic/typed-bytes-array.js';
import '../../offchain-signatures/params/index.js';
import '../../offchain-signatures/params/value.js';
import '../../offchain-signatures/curve-type.js';
import '../../offchain-signatures/params/id.js';
import '../../generic/with-from-dock-id.js';
import '../../offchain-signatures/public-keys/index.js';
import '../../generic/with-prop.js';
import '../../generic/with-props.js';
import '../../../vc/crypto/Bls12381BBDT16KeyPairDock2024.js';
import '@docknetwork/crypto-wasm-ts';
import '../../../vc/crypto/common/DockCryptoKeyPair.js';
import '../../../vc/crypto/Bls12381BBDT16MACDock2024.js';
import '@docknetwork/crypto-wasm-ts/lib/index.js';
import '../../../vc/crypto/common/DockCryptoSignature.js';
import 'jsonld-signatures';
import 'json-stringify-deterministic';
import 'semver/preload.js';
import '../../../vc/crypto/common/CustomLinkedDataSignature.js';
import 'base64url';
import 'jsonld';
import '../../../vc/jws.js';
import '../../../vc/crypto/Bls12381BBDT16MACProofDock2024.js';
import '../../../vc/crypto/common/DockCryptoSignatureProof.js';
import '../../../vc/crypto/Bls12381BBSKeyPairDock2023.js';
import '../../../vc/crypto/Bls12381BBSSignatureDock2022.js';
import '../../../vc/crypto/Bls12381G2KeyPairDock2022.js';
import '../../../vc/crypto/Bls12381BBSSignatureDock2023.js';
import '../../../vc/crypto/Bls12381BBSSignatureProofDock2022.js';
import '../../../vc/crypto/Bls12381BBSSignatureProofDock2023.js';
import '../../../vc/crypto/Bls12381BDDT16KeyPairDock2024.js';
import '../../../vc/crypto/Bls12381BDDT16MACDock2024.js';
import '../../../vc/crypto/Bls12381BDDT16MACProofDock2024.js';
import '../../../vc/crypto/Bls12381PSKeyPairDock2023.js';
import '../../../vc/crypto/Bls12381PSSignatureDock2023.js';
import '../../../vc/crypto/Bls12381PSSignatureProofDock2023.js';
import '@juanelas/base64';
import '../../../keypairs/keypair-secp256k1.js';
import 'elliptic';
import '../../../keypairs/dock-keypair.js';
import '@stablelib/ed25519';
import '@transmute/json-web-signature';
import '../../offchain-signatures/public-keys/value.js';
import '../../offchain-signatures/public-keys/ref.js';
import '../../offchain-signatures/public-keys/id.js';
import '../onchain/verification-method-signature.js';
import '../../../keypairs/did-keypair.js';
import './verification-method-ref-or-ident-ref.js';
import '../../../utils/encoding/base-58.js';
import '../../generic/with-base58.js';
import '../../generic/with-base58btc.js';
import '../../generic/with-multibase.js';
import '../../../utils/encoding/multibase.js';

class Context extends TypedArray {
  static Class = TypedString;
}

class ID extends NamespaceDid {}

class CheqdID extends CheqdNamespaceDid {}

class CheqdTestnetID extends CheqdTestnetDid {}

class CheqdMainnetID extends CheqdMainnetDid {}

class AlsoKnownAs extends TypedArray {
  static Class = NamespaceDid;
}

class Controllers extends TypedArray {
  static Class = NamespaceDid;
}

class CheqdControllers extends TypedArray {
  static Class = CheqdNamespaceDid;
}

class CheqdTestnetControllers extends TypedArray {
  static Class = CheqdTestnetDid;
}

class CheqdMainnetControllers extends TypedArray {
  static Class = CheqdMainnetDid;
}

class VerificationMethods extends TypedArray {
  static Class = VerificationMethod;
}

class CheqdVerificationMethods extends TypedArray {
  static Class = CheqdVerificationMethod;
}

class CheqdTestnetVerificationMethods extends TypedArray {
  static Class = CheqdTestnetVerificationMethod;
}

class CheqdMainnetVerificationMethods extends TypedArray {
  static Class = CheqdMainnetVerificationMethod;
}

class Services extends TypedArray {
  static Class = class ServiceOrDIDCommService {
    static from(value) {
      if (value instanceof Service || value instanceof DIDCommService) {
        return value;
      }

      if (value.type === 'DIDCommMessaging') {
        const se = createServiceEndpoint(value.type, value.serviceEndpoint);
        return Service.fromServiceEndpoint(value.id, se);
      }

      return Service.from(value);
    }
  };
}

class CheqdServices extends TypedArray {
  static Class = CheqdService;
}

class CheqdTestnetServices extends CheqdServices {
  static Class = CheqdTestnetService;
}

class CheqdMainnetServices extends CheqdServices {
  static Class = CheqdMainnetService;
}

class VerificationMethodReferences extends TypedArray {
  static Class = VerificationMethodRef;
}

class CheqdVerificationMethodReferences extends TypedArray {
  static Class = CheqdVerificationMethodRef;
}

class CheqdTestnetVerificationMethodReferences extends TypedArray {
  static Class = CheqdTestnetVerificationMethodRef;
}

class CheqdMainnetVerificationMethodReferences extends TypedArray {
  static Class = CheqdMainnetVerificationMethodRef;
}

class VersionId extends TypedUUID {}

class CheqdAssertionMethod extends TypedArray {
  static Class = CheqdVerificationMethodRefOrCheqdVerificationMethod;
}

class CheqdTestnetAssertionMethod extends TypedArray {
  static Class = CheqdTestnetVerificationMethodOrCheqdTestnetVerificationMethodRef;
}

class CheqdMainnetAssertionMethod extends TypedArray {
  static Class = CheqdMainnetVerificationMethodOrCheqdMainnetVerificationMethodRef;
}

class DIDDocument extends withFrom(
  TypedStruct,
  (value, from) => from(value instanceof CheqdDIDDocument ? value.toDIDDocument() : value), // eslint-disable-line no-use-before-define
) {
  static Classes = {
    '@context': Context,
    id: ID,
    alsoKnownAs: option(AlsoKnownAs),
    controller: Controllers,
    verificationMethod: VerificationMethods,
    service: option(Services),
    authentication: option(VerificationMethodReferences),
    assertionMethod: option(VerificationMethodReferences),
    keyAgreement: option(VerificationMethodReferences),
    capabilityInvocation: option(VerificationMethodReferences),
    capabilityDelegation: option(VerificationMethodReferences),
    [ATTESTS_IRI]: option(TypedString),
  };

  static create(
    did,
    keys = [],
    controllers = [],
    serviceEndpoints = {},
    {
      context = [CONTEXT_URI],
      alsoKnownAs = [],
      capabilityDelegation = [],
      attests = null,
    } = {},
  ) {
    const doc = new this(
      context,
      did,
      alsoKnownAs,
      controllers,
      [],
      [],
      [],
      [],
      [],
      [],
      capabilityDelegation,
      attests,
    );

    let keyIdx = 0;
    const keysWithRefs = Array.isArray(keys)
      ? keys.map((key) => [[did, ++keyIdx], key])
      : Object.entries(keys);

    for (const [keyRef, didKey] of keysWithRefs) {
      doc.addKey(keyRef, didKey);
    }
    if (serviceEndpoints) {
      for (const [id, serviceEndpoint] of Object.entries(serviceEndpoints)) {
        doc.addServiceEndpoint([did, id], serviceEndpoint);
      }
    }

    return doc;
  }

  addKey(keyRef, didKey) {
    const ref = VerificationMethodRef.from(keyRef);
    const key = DidKey.from(didKey);

    if (this.verificationMethod.find((existing) => existing.id.eq(ref))) {
      throw new Error(`Verification method \`${ref}\` already exists`);
    }

    if (key.verRels.isAuthentication()) {
      this.authentication ||= [];
      this.authentication.push(ref);
    }
    if (key.verRels.isAssertion()) {
      this.assertionMethod ||= [];
      this.assertionMethod.push(ref);
    }
    if (key.verRels.isKeyAgreement()) {
      this.keyAgreement ||= [];
      this.keyAgreement.push(ref);
    }
    if (key.verRels.isCapabilityInvocation()) {
      this.capabilityInvocation ||= [];
      this.capabilityInvocation.push(ref);
    }

    this.verificationMethod.push(VerificationMethod.fromDidKey(ref, key));

    return this;
  }

  addController(controller) {
    if (this.controller.some((ctrl) => ctrl.eq(controller))) {
      throw new Error(`Controller \`${controller}\` already exists`);
    }
    this.controller.push(controller);

    return this;
  }

  addServiceEndpoint(id, serviceEndpoint) {
    if (this.service.some((service) => service.id.eq(id))) {
      throw new Error(`Service endpoint with id \`${id}\` already exists`);
    }
    this.service.push(Service.fromServiceEndpoint(id, serviceEndpoint));

    return this;
  }

  removeKey(keyRef) {
    const ref = VerificationMethodRef.from(keyRef);
    const keyIndex = this.verificationMethod.findIndex((method) => method.id.eq(ref));

    // eslint-disable-next-line no-bitwise
    if (~keyIndex) {
      this.verificationMethod.splice(keyIndex, 1);
    } else {
      throw new Error(`Verification method with id \`${ref}\` doesn't exist`);
    }

    const isNotRef = (value) => !(value.ref ?? value).eq(ref);

    this.assertionMethod = this.assertionMethod?.filter(isNotRef);
    this.authentication = this.authentication?.filter(isNotRef);
    this.keyAgreement = this.keyAgreement?.filter(isNotRef);
    this.capabilityInvocation = this.capabilityInvocation?.filter(isNotRef);
    this.capabilityDelegation = this.capabilityDelegation?.filter(isNotRef);

    return this;
  }

  removeController(controller) {
    const idx = this.controller.findIndex((ctrl) => ctrl.eq(controller));
    // eslint-disable-next-line
    if (!~idx) {
      throw new Error(`Controller \`${controller}\` doesn't exist`);
    }
    this.controller.splice(idx, 1);

    return this;
  }

  removeServiceEndpoint(id) {
    const idx = this.service.findIndex((service) => service.id.eq(id));
    // eslint-disable-next-line
    if (!~idx) {
      throw new Error(`Service endpoint \`${id}\` doesnt exist`);
    }
    this.service.splice(idx, 1);

    return this;
  }

  nextKeyIndex() {
    return TypedNumber.from(
      [...this.verificationMethod].reduce(
        (max, { id: { index } }) => Math.max(max, index ?? 0),
        0,
      ),
    ).inc();
  }

  get attests() {
    return this[ATTESTS_IRI];
  }

  get publicKey() {
    return this.verificationMethod;
  }

  set attests(iri) {
    this[ATTESTS_IRI] = iri;
  }

  setAttests(iri) {
    this.attests = iri;

    return this;
  }

  didKeys() {
    const {
      verificationMethod,
      authentication,
      assertionMethod,
      keyAgreement,
      capabilityInvocation,
    } = this;

    class VerMethodRefSet extends TypedSet {
      static Class = VerificationMethodRef;
    }

    const auth = new VerMethodRefSet(authentication);
    const assertion = new VerMethodRefSet(assertionMethod);
    const keyAgr = new VerMethodRefSet(keyAgreement);
    const capInv = new VerMethodRefSet(capabilityInvocation);

    const keys = [...verificationMethod].map((method) => {
      const verRels = new VerificationRelationship();

      if (auth.has(method.id)) {
        verRels.setAuthentication();
      }
      if (assertion.has(method.id)) {
        verRels.setAssertion();
      }
      if (keyAgr.has(method.id)) {
        verRels.setKeyAgreement();
      }
      if (capInv.has(method.id)) {
        verRels.setCapabilityInvocation();
      }

      return [method.id, new DidKey(method.publicKey(), verRels)];
    });

    return new DidKeys(keys);
  }

  // eslint-disable-next-line no-use-before-define
  toCheqd(Class = CheqdDIDDocument, versionId = TypedUUID.random()) {
    const {
      '@context': context,
      id,
      alsoKnownAs,
      controller,
      verificationMethod,
      authentication,
      assertionMethod,
      capabilityInvocation,
      capabilityDelegation,
      keyAgreement,
      service,
    } = this;

    // eslint-disable-next-line no-use-before-define
    return new (ensureEqualToOrPrototypeOf(CheqdDIDDocument, Class))(
      context,
      id,
      alsoKnownAs,
      controller,
      verificationMethod,
      service,
      authentication,
      assertionMethod,
      keyAgreement,
      capabilityInvocation,
      capabilityDelegation,
      versionId,
    );
  }
}

class CheqdDIDDocument extends TypedStruct {
  static Classes = {
    context: Context,
    id: CheqdID,
    alsoKnownAs: option(AlsoKnownAs),
    controller: CheqdControllers,
    verificationMethod: CheqdVerificationMethods,
    service: option(CheqdServices),
    authentication: CheqdVerificationMethodReferences,
    assertionMethod: option(CheqdAssertionMethod),
    keyAgreement: option(CheqdVerificationMethodReferences),
    capabilityInvocation: option(CheqdVerificationMethodReferences),
    capabilityDelegation: option(CheqdVerificationMethodReferences),
    versionId: option(VersionId),
  };

  constructor(...args) {
    super(...args);

    const { verificationMethod } = this;

    this.verificationMethod = verificationMethod.filter(
      (verMethod) => !verMethod.isOffchain()
        && !verMethod.verificationMaterial.bytes.every((item) => !item),
    );
    const offchainVerMethod = verificationMethod.filter((verMethod) => verMethod.isOffchain());

    this.assertionMethod = [
      ...(this.assertionMethod ? this.assertionMethod.filter(
        (ref) => !offchainVerMethod.some((verMethod) => verMethod.id.eq(ref)),
      ) : []),
      ...offchainVerMethod,
    ];
  }

  toDIDDocument() {
    const {
      context,
      id,
      alsoKnownAs,
      controller,
      verificationMethod,
      authentication,
      assertionMethod,
      capabilityInvocation,
      capabilityDelegation,
      keyAgreement,
      service,
    } = this;

    // Convert CheqdService objects to Service objects
    const convertedServices = [...service].map((cheqdService) => {
      // Create a ServiceEndpoint object from the CheqdService data
      const serviceEndpointArray = cheqdService.serviceEndpoint.toJSON();
      const serviceEndpoint = createServiceEndpoint(cheqdService.serviceType, serviceEndpointArray);
      // Convert the Cheqd-specific ID to a generic ID
      const genericId = ServiceEndpointId.from(cheqdService.id.toJSON());
      return Service.fromServiceEndpoint(genericId, serviceEndpoint);
    });

    const assertionMethodOffchainKeys = [...assertionMethod].filter(
      (keyRefOrKey) => keyRefOrKey.id,
    );
    const verificationMethodWithOffchainKeys = [
      ...verificationMethod,
      ...assertionMethodOffchainKeys,
    ];
    const assertionMethodOnlyRefs = [...assertionMethod].map(
      (keyRefOrKey) => keyRefOrKey.id ?? keyRefOrKey,
    );

    return new DIDDocument(
      context,
      id,
      alsoKnownAs,
      controller,
      verificationMethodWithOffchainKeys,
      convertedServices,
      authentication,
      assertionMethodOnlyRefs,
      keyAgreement,
      capabilityInvocation,
      capabilityDelegation,
      null,
    );
  }
}

class CheqdTestnetDIDDocument extends CheqdDIDDocument {
  static Classes = {
    context: Context,
    id: CheqdTestnetID,
    alsoKnownAs: option(AlsoKnownAs),
    controller: CheqdTestnetControllers,
    verificationMethod: CheqdTestnetVerificationMethods,
    service: option(CheqdTestnetServices),
    authentication: CheqdTestnetVerificationMethodReferences,
    assertionMethod: option(CheqdTestnetAssertionMethod),
    keyAgreement: option(CheqdTestnetVerificationMethodReferences),
    capabilityInvocation: option(CheqdTestnetVerificationMethodReferences),
    capabilityDelegation: option(CheqdTestnetVerificationMethodReferences),
    versionId: option(VersionId),
  };
}

class CheqdMainnetDIDDocument extends CheqdDIDDocument {
  static Classes = {
    context: Context,
    id: CheqdMainnetID,
    alsoKnownAs: option(AlsoKnownAs),
    controller: CheqdMainnetControllers,
    verificationMethod: CheqdMainnetVerificationMethods,
    service: option(CheqdMainnetServices),
    authentication: CheqdMainnetVerificationMethodReferences,
    assertionMethod: option(CheqdMainnetAssertionMethod),
    keyAgreement: option(CheqdMainnetVerificationMethodReferences),
    capabilityInvocation: option(CheqdMainnetVerificationMethodReferences),
    capabilityDelegation: option(CheqdMainnetVerificationMethodReferences),
    versionId: option(VersionId),
  };
}

export { ATTESTS_IRI, CONTEXT_URI, CheqdDIDDocument, CheqdMainnetDIDDocument, CheqdMainnetService, CheqdMainnetVerificationMethod, CheqdMainnetVerificationMethodReferences, CheqdService, CheqdTestnetDIDDocument, CheqdTestnetService, CheqdTestnetVerificationMethod, CheqdTestnetVerificationMethodReferences, CheqdVerificationMethod, CheqdVerificationMethodReferences, DIDCommService, DIDDocument, Service, ServiceEndpointId, Services, VerificationMethod, VerificationMethodRef, VerificationMethodReferences, VersionId, createServiceEndpoint };
//# sourceMappingURL=index.js.map
