'use strict';

require('../../../utils/types/array.cjs');
var utils_types_bytes = require('../../../utils/types/bytes.cjs');
var utils_interfaces = require('../../../utils/interfaces.cjs');
var utils_inheritance = require('../../../utils/inheritance.cjs');
require('bs58');
require('multiformats/bases/base58');
require('varint');
require('../../../utils/encoding/ss-58.cjs');
var types_generic_typedEnum = require('../../generic/typed-enum.cjs');
require('../../generic/typed-bytes.cjs');
var types_generic_typedString = require('../../generic/typed-string.cjs');
var types_generic_createPlaceholder = require('../../generic/create-placeholder.cjs');
var types_generic_typedArray = require('../../generic/typed-array.cjs');
require('../../generic/typed-tuple.cjs');
require('../../generic/typed-null.cjs');
var types_generic_typedNumber = require('../../generic/typed-number.cjs');
require('../../generic/typed-set.cjs');
var types_generic_typedMap = require('../../generic/typed-map.cjs');
var types_generic_typedStruct = require('../../generic/typed-struct.cjs');
require('uuid');
require('js-sha256');
var types_generic_withFrom = require('../../generic/with-from.cjs');
var types_generic_withProp = require('../../generic/with-prop.cjs');
var types_did_document_identRef = require('./ident-ref.cjs');
require('../onchain/typed-did/index.cjs');
require('../onchain/did-key.cjs');
require('../onchain/verification-method-signature.cjs');
var types_did_onchain_typedDid_cheqdDid = require('../onchain/typed-did/cheqd-did.cjs');
require('../../../utils/types/object.cjs');
require('../../../utils/types/iterable.cjs');
require('../../../utils/types/set.cjs');
require('crypto');
require('../../../utils/types/string.cjs');
require('../../../utils/assert.cjs');
require('../../../utils/error.cjs');
require('blake2b');
require('../../generic/with-base.cjs');
require('../../generic/with-catch-null.cjs');
require('../../generic/with-eq.cjs');
require('../../generic/any-of.cjs');
require('../../generic/with-from-json-bytes.cjs');
require('../../generic/with-props.cjs');
require('../../generic/with-qualifier.cjs');
require('../onchain/typed-did/did-method-key/did-method-key-public-key.cjs');
require('../../../utils/encoding/base-58-btc.cjs');
require('../../generic/sized.cjs');
require('../../../utils/types/number.cjs');
require('../../public-keys/public-key.cjs');
require('../../public-keys/public-key-x25519-value.cjs');
require('../../public-keys/public-key-ed25519-value.cjs');
require('../../../vc/crypto/constants.cjs');
require('../../public-keys/public-key-secp256k1-value.cjs');
require('../../public-keys/public-key-sr25519-value.cjs');
require('../onchain/constants.cjs');
require('../onchain/typed-did/signature.cjs');
require('../onchain/typed-did/did-method-key/did-method-key-signature.cjs');
require('../../signatures/signature-value.cjs');
require('../../signatures/signature-ed25519-value.cjs');
require('../../signatures/signature-secp256k1-value.cjs');
require('../../signatures/signature.cjs');
require('../../signatures/signature-sr25519-value.cjs');
require('../onchain/typed-did/dock-did-value.cjs');
require('../../generic/typed-uuid.cjs');
require('../../generic/utils.cjs');
require('../../generic/typed-bytes-array.cjs');
require('../../offchain-signatures/params/index.cjs');
require('../../offchain-signatures/params/value.cjs');
require('../../generic/option.cjs');
require('../../offchain-signatures/curve-type.cjs');
require('../../offchain-signatures/params/id.cjs');
require('../../generic/with-from-dock-id.cjs');
require('../../offchain-signatures/public-keys/index.cjs');
require('../../../vc/crypto/Bls12381BBDT16KeyPairDock2024.cjs');
require('@docknetwork/crypto-wasm-ts');
require('../../../vc/crypto/common/DockCryptoKeyPair.cjs');
require('../../../vc/crypto/Bls12381BBDT16MACDock2024.cjs');
require('@docknetwork/crypto-wasm-ts/lib/index.js');
require('../../../vc/crypto/common/DockCryptoSignature.cjs');
require('jsonld-signatures');
require('json-stringify-deterministic');
require('semver/preload.js');
require('../../../vc/crypto/common/CustomLinkedDataSignature.cjs');
require('base64url');
require('jsonld');
require('./verification-method-ref.cjs');
require('../../../vc/jws.cjs');
require('../../../vc/crypto/Bls12381BBDT16MACProofDock2024.cjs');
require('../../../vc/crypto/common/DockCryptoSignatureProof.cjs');
require('../../../vc/crypto/Bls12381BBSKeyPairDock2023.cjs');
require('../../../vc/crypto/Bls12381BBSSignatureDock2022.cjs');
require('../../../vc/crypto/Bls12381G2KeyPairDock2022.cjs');
require('../../../vc/crypto/Bls12381BBSSignatureDock2023.cjs');
require('../../../vc/crypto/Bls12381BBSSignatureProofDock2022.cjs');
require('../../../vc/crypto/Bls12381BBSSignatureProofDock2023.cjs');
require('../../../vc/crypto/Bls12381BDDT16KeyPairDock2024.cjs');
require('../../../vc/crypto/Bls12381BDDT16MACDock2024.cjs');
require('../../../vc/crypto/Bls12381BDDT16MACProofDock2024.cjs');
require('../../../vc/crypto/Bls12381PSKeyPairDock2023.cjs');
require('../../../vc/crypto/Bls12381PSSignatureDock2023.cjs');
require('../../../vc/crypto/Bls12381PSSignatureProofDock2023.cjs');
require('@juanelas/base64');
require('../../../keypairs/keypair-secp256k1.cjs');
require('elliptic');
require('../../../keypairs/dock-keypair.cjs');
require('@stablelib/ed25519');
require('@transmute/json-web-signature');
require('../../offchain-signatures/public-keys/value.cjs');
require('../../offchain-signatures/public-keys/ref.cjs');
require('../../offchain-signatures/public-keys/id.cjs');
require('../onchain/verification-relationship.cjs');
require('../../../keypairs/did-keypair.cjs');
require('./verification-method-ref-or-ident-ref.cjs');

/* eslint no-use-before-define: 0 */
/* eslint-disable sonarjs/cognitive-complexity */
/* eslint-disable sonarjs/no-identical-functions */
/* eslint-disable sonarjs/no-all-duplicated-branches */


function ensureIsURI(str) {
  const uriRegex = /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/;
  if (!uriRegex.test(str)) {
    throw new Error(`Invalid URI: ${str}`);
  }
}

class ServiceEndpointId extends types_did_document_identRef {}

class CheqdServiceEndpointId extends types_did_document_identRef {
  static Did = types_did_onchain_typedDid_cheqdDid.CheqdDid;
}

class CheqdTestnetServiceEndpointId extends ServiceEndpointId {
  static Did = types_did_onchain_typedDid_cheqdDid.CheqdTestnetDid;
}

class CheqdMainnetServiceEndpointId extends ServiceEndpointId {
  static Did = types_did_onchain_typedDid_cheqdDid.CheqdMainnetDid;
}

class SuffixServiceEndpointId extends types_generic_withFrom(
  types_generic_typedString,
  (value, from) => from(utils_types_bytes.isBytes(value) ? value : ServiceEndpointId.from(value)[1]),
) {}

const UnknownServicePlaceholder = types_generic_createPlaceholder((value) => {
  if (
    +utils_interfaces.maybeToNumber(value) === 0b1000
    || (String(value) !== 'LinkedDomains' && String(value) !== 'DIDCommMessaging')
    || value == null
  ) {
    return 0b1000;
  } else {
    throw new Error(`Unknown value \`${utils_interfaces.maybeToJSONString(value)}\``);
  }
});

const LinkedDomainsPlaceholder = types_generic_createPlaceholder((value) => {
  if (
    +utils_interfaces.maybeToNumber(value) === 0b0001
    || String(value) === 'LinkedDomains'
    || value == null
  ) {
    return 0b0001;
  } else {
    throw new Error(`Unknown value \`${utils_interfaces.maybeToJSONString(value)}\``);
  }
});

const DIDCommMessagingPlaceholder = types_generic_createPlaceholder((value) => {
  if (
    +utils_interfaces.maybeToNumber(value) === 0b0010
    || String(value) === 'DIDCommMessaging'
    || value == null
  ) {
    return 0b0010;
  } else {
    throw new Error(`Unknown value \`${utils_interfaces.maybeToJSONString(value)}\``);
  }
});

class ServiceEndpointType extends types_generic_typedEnum {
  static fromApi(value) {
    return this.from(value);
  }

  static fromJSON(value) {
    return this.from(value);
  }

  static from(value) {
    // Convert string values to the appropriate variant
    if (typeof value === 'string') {
      switch (value) {
        case 'LinkedDomains':
          // eslint-disable-next-line no-use-before-define
          return new LinkedDomains();
        case 'DIDCommMessaging':
          // eslint-disable-next-line no-use-before-define
          return new DIDCommMessaging();
        default:
          // eslint-disable-next-line no-use-before-define
          return new UnknownServiceEndpoint(value);
      }
    }

    // If it's already an instance of a variant, return it
    // eslint-disable-next-line no-use-before-define
    if (value instanceof LinkedDomains || value instanceof DIDCommMessaging || value instanceof UnknownServiceEndpoint) {
      return value;
    }

    // Otherwise, try to create a LinkedDomains as default
    // eslint-disable-next-line no-use-before-define
    return new LinkedDomains();
  }
}

class UnknownServiceEndpoint extends ServiceEndpointType {
  static Type = 'ServiceEndpoint';

  static Class = UnknownServicePlaceholder;

  constructor(knownType) {
    super();
    this.knownType = knownType;
  }

  toJSON() {
    return this.knownType;
  }

  apply(fn) {
    return fn(this.knownType);
  }
}

class LinkedDomains extends ServiceEndpointType {
  static Type = 'LinkedDomains';

  static Class = LinkedDomainsPlaceholder;

  toJSON() {
    return this.constructor.Type;
  }

  apply(fn) {
    return fn(this.constructor.Type);
  }
}

class DIDCommMessaging extends ServiceEndpointType {
  static Type = 'DIDCommMessaging';

  static Class = DIDCommMessagingPlaceholder;

  toJSON() {
    return this.constructor.Type;
  }

  apply(fn) {
    return fn(this.constructor.Type);
  }
}

ServiceEndpointType.bindVariants(LinkedDomains, DIDCommMessaging, UnknownServiceEndpoint);

class ServiceEndpointOrigin extends types_generic_typedString {}

class ServiceEndpointOrigins extends types_generic_typedArray {
  static Class = ServiceEndpointOrigin;
}

class DIDCommServiceEndpoint extends types_generic_typedStruct {
  static Classes = {
    uri: types_generic_typedString,
    accept: class AcceptArray extends types_generic_typedArray {
      static Class = types_generic_typedString;
    },
    routingKeys: class RoutingKeysArray extends types_generic_typedArray {
      static Class = types_generic_typedString;
    },
    recipientKeys: class RecipientKeysArray extends types_generic_typedArray {
      static Class = types_generic_typedString;
    },
    priority: class PriorityNumber extends types_generic_typedNumber { },
  };

  constructor(uri, accept = [], routingKeys = [], recipientKeys = [], priority = 0) {
    super(uri, accept, routingKeys, recipientKeys, priority);
  }

  toJSON() {
    return {
      uri: this.uri.toJSON(),
      accept: this.accept.toJSON(),
      routingKeys: this.routingKeys.toJSON(),
      recipientKeys: this.recipientKeys.toJSON(),
      priority: this.priority.toJSON(),
    };
  }

  static from(value) {
    if (typeof value === 'string') {
      ensureIsURI(value);
      return new DIDCommServiceEndpoint(value, [], []);
    } else if (value && typeof value === 'object') {
      const uri = value.uri || '';
      const accept = Array.isArray(value.accept) ? value.accept : [];
      const routingKeys = Array.isArray(value.routingKeys) ? value.routingKeys : [];
      const recipientKeys = Array.isArray(value.recipientKeys) ? value.recipientKeys : [];
      const priority = value.priority !== undefined ? value.priority : 0;
      ensureIsURI(uri);
      return new DIDCommServiceEndpoint(uri, accept, routingKeys, recipientKeys, priority);
    } else {
      throw new Error(`Invalid DIDComm service endpoint: ${value}`);
    }
  }
}

class DIDCommServiceEndpoints extends types_generic_typedArray {
  static Class = DIDCommServiceEndpoint;
}

class ServiceEndpoint extends types_generic_typedStruct {
  static Classes = {
    types: ServiceEndpointType,
    origins: ServiceEndpointOrigins,
  };

  constructor(type, origins) {
    super(type, origins);
  }
}

function createServiceType(type) {
  if (typeof type === 'string') {
    switch (type) {
      case 'LinkedDomains':
        return new LinkedDomains();
      case 'DIDCommMessaging':
        return new DIDCommMessaging();
      default:
        return new UnknownServiceEndpoint(type);
    }
  } else if (type instanceof LinkedDomains || type instanceof DIDCommMessaging || type instanceof UnknownServiceEndpoint) {
    return type;
  } else {
    throw new Error(`Invalid service type: ${type}`);
  }
}

function processDIDCommOrigins(origins) {
  if (!Array.isArray(origins)) {
    return origins;
  }

  const processedOrigins = new DIDCommServiceEndpoints();
  origins.forEach((origin) => {
    if (typeof origin === 'string') {
      // Simple URI string
      processedOrigins.push(DIDCommServiceEndpoint.from({ uri: origin }));
    } else if (origin && typeof origin === 'object') {
      // Complex DIDComm object
      processedOrigins.push(DIDCommServiceEndpoint.from(origin));
    } else {
      throw new Error(`Invalid DIDComm origin: ${origin}`);
    }
  });
  return processedOrigins;
}

function createServiceEndpoint(type, origins) {
  const serviceType = createServiceType(type);

  if (serviceType instanceof LinkedDomains) {
    return new ServiceEndpoint(serviceType, origins);
  }

  if (serviceType instanceof UnknownServiceEndpoint) {
    return new ServiceEndpoint(serviceType, origins);
  }

  if (serviceType instanceof DIDCommMessaging) {
    const processedOrigins = processDIDCommOrigins(origins);

    const instance = Object.create(ServiceEndpoint.prototype);
    instance.types = serviceType;
    instance.origins = processedOrigins;
    Object.seal(instance);
    return instance;
  }

  throw new Error(`Unsupported service type: ${serviceType}`);
}

class Service extends types_generic_typedStruct {
  static Classes = {
    id: ServiceEndpointId,
    type: ServiceEndpointType,
    serviceEndpoint: class ServiceEndpoints extends types_generic_typedArray {
      static Class = class ServiceEndpointString extends types_generic_typedString {};
    },
  };

  constructor(id, type, serviceEndpoint) {
    super(id, type, serviceEndpoint);
  }

  static fromServiceEndpoint(id, serviceEndpoint) {
    // For DIDComm services, use a specialized class
    if (serviceEndpoint.types instanceof DIDCommMessaging) {
      return DIDCommService.fromServiceEndpoint(id, serviceEndpoint);
    }

    return new this(id, serviceEndpoint.types, serviceEndpoint.origins);
  }

  static from(value) {
    // If it's already a Service instance, return it
    if (value instanceof Service) {
      return value;
    }

    // If it's a DIDCommService instance, return it as-is (don't convert)
    if (value instanceof DIDCommService) {
      return value;
    }

    // Otherwise, use the parent TypedStruct.from method
    return super.from(value);
  }

  toJSON() {
    const result = {
      id: this.id.toJSON(),
      type: this.type.toJSON(),
      serviceEndpoint: this.serviceEndpoint.toJSON(),
    };

    // For DIDComm services, convert the structured data to objects
    if (this.type instanceof DIDCommMessaging) {
      result.serviceEndpoint = result.serviceEndpoint.map((endpoint) => {
        if (typeof endpoint === 'string') {
          // If it's a string, it might be a simple URI
          return {
            uri: endpoint, accept: [], routingKeys: [], recipientKeys: [], priority: 0,
          };
        }
        return endpoint;
      });
    }

    return result;
  }

  // eslint-disable-next-line no-use-before-define
  toCheqd(Class = CheqdService) {
    let processedServiceEndpoint = this.serviceEndpoint;

    if (this.type instanceof DIDCommMessaging) {
      const originalArray = this.serviceEndpoint.toJSON();
      const processedArray = originalArray.map((endpoint) => {
        if (typeof endpoint === 'string') {
          // Try to parse JSON string and convert to structured object
          try {
            const parsed = JSON.parse(endpoint);
            if (parsed && typeof parsed === 'object' && parsed.uri) {
              return {
                uri: parsed.uri || '',
                accept: parsed.accept || [],
                routingKeys: parsed.routingKeys || [],
                recipientKeys: parsed.recipientKeys || [],
                priority: parsed.priority || 0,
              };
            }
          } catch {
            // If parsing fails, return as-is
            ensureIsURI(endpoint);
          }
          return endpoint;
        } else if (endpoint && typeof endpoint === 'object') {
          // For DIDComm objects, pass them as structured objects, not JSON strings
          return {
            uri: endpoint.uri || '',
            accept: endpoint.accept || [],
            routingKeys: endpoint.routingKeys || [],
            recipientKeys: endpoint.recipientKeys || [],
            priority: endpoint.priority || 0,
          };
        } else {
          return endpoint;
        }
      });
      processedServiceEndpoint = processedArray;
    }

    // eslint-disable-next-line no-use-before-define
    return new (utils_inheritance.ensureEqualToOrPrototypeOf(CheqdService, Class))(
      this.id,
      this.type,
      processedServiceEndpoint,
    );
  }
}

class DIDCommServiceEndpointValue {
  constructor(value) {
    this.value = value;
  }

  eq(other) {
    const thisJSON = JSON.stringify({
      ...this.toJSON(),
      id: undefined,
    });
    const otherJSON = JSON.stringify({
      ...other.toJSON(),
      id: undefined,
    });
    return thisJSON === otherJSON;
  }

  toJSON() {
    return this.value;
  }

  static from(value) {
    return new this(value);
  }
}

class DIDCommServiceEndpointsArray extends types_generic_typedArray {
  static Class = DIDCommServiceEndpointValue;
}

class DIDCommService extends types_generic_typedStruct {
  static Classes = {
    id: ServiceEndpointId,
    type: ServiceEndpointType,
    serviceEndpoint: DIDCommServiceEndpointsArray,
  };

  constructor(id, type, serviceEndpoint) {
    super(id, type, serviceEndpoint);
  }

  static fromServiceEndpoint(id, serviceEndpoint) {
    // Convert DIDCommServiceEndpoints to a format that DIDCommService can handle
    const convertedEndpoints = [];
    serviceEndpoint.origins.forEach((origin) => {
      if (origin instanceof DIDCommServiceEndpoint) {
        // Convert the structured endpoint to a proper object
        const endpointObj = {
          uri: origin.uri.toJSON(),
          accept: origin.accept.toJSON(),
          routingKeys: origin.routingKeys.toJSON(),
          recipientKeys: origin.recipientKeys.toJSON(),
          priority: origin.priority.toJSON(),
        };
        convertedEndpoints.push(endpointObj);
      } else {
        convertedEndpoints.push(origin);
      }
    });

    return new this(id, serviceEndpoint.types, convertedEndpoints);
  }

  toCheqd(Class = CheqdService) {
    // Process the serviceEndpoint to ensure it's in the right format
    let processedServiceEndpoint = this.serviceEndpoint;

    // Convert the serviceEndpoint to a format that CheqdService can handle
    if (Array.isArray(this.serviceEndpoint) && typeof this.serviceEndpoint.map === 'function') {
      const processedArray = this.serviceEndpoint.map((endpoint) => {
        if (typeof endpoint === 'string') {
          // Try to parse JSON string and convert to structured object
          try {
            const parsed = JSON.parse(endpoint);
            if (parsed && typeof parsed === 'object' && parsed.uri) {
              return {
                uri: parsed.uri || '',
                accept: parsed.accept || [],
                routingKeys: parsed.routingKeys || [],
                recipientKeys: parsed.recipientKeys || [],
                priority: parsed.priority || 0,
              };
            }
          } catch {
            // If parsing fails, return as-is
            ensureIsURI(endpoint);
          }
          return endpoint;
        } else if (endpoint && typeof endpoint === 'object') {
          // For DIDComm objects, pass them as structured objects, not JSON strings
          return {
            uri: endpoint.uri || '',
            accept: endpoint.accept || [],
            routingKeys: endpoint.routingKeys || [],
            recipientKeys: endpoint.recipientKeys || [],
            priority: endpoint.priority || 0,
          };
        } else {
          return endpoint;
        }
      });
      processedServiceEndpoint = processedArray;
    } else if (this.serviceEndpoint && typeof this.serviceEndpoint.toJSON === 'function') {
      // Handle TypedArray (DIDCommServiceEndpoints)
      const endpoints = this.serviceEndpoint.toJSON();
      if (Array.isArray(endpoints)) {
        const processedArray = endpoints.map((endpoint) => {
          if (typeof endpoint === 'string') {
            // Try to parse JSON string and convert to structured object
            try {
              const parsed = JSON.parse(endpoint);
              if (parsed && typeof parsed === 'object' && parsed.uri) {
                return {
                  uri: parsed.uri || '',
                  accept: parsed.accept || [],
                  routingKeys: parsed.routingKeys || [],
                  recipientKeys: parsed.recipientKeys || [],
                  priority: parsed.priority || 0,
                };
              }
            } catch {
              // If parsing fails, return as-is
              ensureIsURI(endpoint);
            }
            return endpoint;
          } else if (endpoint && typeof endpoint === 'object') {
          // For DIDComm objects, pass them as structured objects, not JSON strings
            return {
              uri: endpoint.uri || '',
              accept: endpoint.accept || [],
              routingKeys: endpoint.routingKeys || [],
              recipientKeys: endpoint.recipientKeys || [],
              priority: endpoint.priority || 0,
            };
          } else {
            return endpoint;
          }
        });
        processedServiceEndpoint = processedArray;
      }
    }

    // eslint-disable-next-line no-use-before-define
    return new (utils_inheritance.ensureEqualToOrPrototypeOf(CheqdService, Class))(
      this.id,
      this.type,
      processedServiceEndpoint,
    );
  }
}

class ServiceEndpointValue {
  constructor(value) {
    // Store the value directly without any conversion
    this.value = value;
  }

  toJSON() {
    return this.value;
  }

  static from(value) {
    return new this(value);
  }
}

class ServiceEndpointsType extends types_generic_typedArray {
  static Class = ServiceEndpointValue;
}

class CheqdService extends types_generic_withFrom(
  types_generic_typedStruct,
  function from(value, fromFn) {
    if (value instanceof Service) {
      return fromFn(value.toCheqd(this));
    }

    if (value instanceof DIDCommService) {
      return fromFn(value.toCheqd(this));
    }

    // Handle flattened format from blockchain for DIDComm services
    if (value && typeof value === 'object' && value.serviceType === 'DIDCommMessaging' && value.accept && value.routingKeys) {
      // Reconstruct the structured format from the flattened format
      const reconstructedEndpoints = value.serviceEndpoint.map((uri) => ({
        uri,
        accept: value.accept || [],
        routingKeys: value.routingKeys || [],
        recipientKeys: value.recipientKeys || [],
        priority: value.priority || 0,
      }));

      const reconstructedValue = {
        id: value.id,
        serviceType: value.serviceType,
        serviceEndpoint: reconstructedEndpoints,
      };

      return fromFn(reconstructedValue);
    }

    if (value && typeof value === 'object' && !value.serviceType && value.type) {
      return fromFn({
        id: value.id,
        serviceType: value.type,
        serviceEndpoint: value.serviceEndpoint,
      });
    }

    return fromFn(value);
  },
) {
  static Classes = {
    id: CheqdServiceEndpointId,
    serviceType: ServiceEndpointType,
    serviceEndpoint: ServiceEndpointsType,
  };

  constructor(id, serviceType, serviceEndpoint) {
    // Handle string serviceType values by converting them to ServiceEndpointType instances
    let processedServiceType = serviceType;
    if (typeof serviceType === 'string') {
      processedServiceType = ServiceEndpointType.from(serviceType);
    }

    super(id, processedServiceType, serviceEndpoint);

    // For DIDComm services, ensure the serviceEndpoint is properly wrapped
    if (processedServiceType instanceof DIDCommMessaging && Array.isArray(serviceEndpoint)) {
      const ServiceEndpointArray = this.constructor.Classes.serviceEndpoint;
      const processedServiceEndpoint = new ServiceEndpointArray();

      serviceEndpoint.forEach((endpoint) => {
        if (typeof endpoint === 'string') {
          processedServiceEndpoint.push(endpoint);
        } else if (endpoint && typeof endpoint === 'object') {
          // Store the structured object directly
          processedServiceEndpoint.push(endpoint);
        } else {
          processedServiceEndpoint.push(endpoint);
        }
      });

      this.serviceEndpoint = processedServiceEndpoint;
    }
  }

  static fromServiceEndpoint(id, serviceEndpoint) {
    return new this(id, serviceEndpoint.serviceType, serviceEndpoint.serviceEndpoint);
  }

  static fromCheqdPayload(payload) {
    // Handle the case where the payload comes back in flattened format from the blockchain
    if (payload.serviceType === 'DIDCommMessaging' && payload.accept && payload.routingKeys) {
      // Reconstruct the structured format from the flattened format
      const reconstructedEndpoints = payload.serviceEndpoint.map((uri) => ({
        uri,
        accept: payload.accept || [],
        routingKeys: payload.routingKeys || [],
        recipientKeys: payload.recipientKeys || [],
        priority: payload.priority || 0,
      }));

      return new this(payload.id, payload.serviceType, reconstructedEndpoints);
    }

    // For other service types or non-flattened format, use the regular constructor
    return new this(payload.id, payload.serviceType, payload.serviceEndpoint);
  }

  toJSON() {
    const result = {
      id: this.id.toJSON(),
      type: this.serviceType.toJSON(),
      serviceEndpoint: this.serviceEndpoint.toJSON(),
    };

    // For DIDComm services, ensure endpoints are in object format
    if (this.serviceType instanceof DIDCommMessaging) {
      result.serviceEndpoint = result.serviceEndpoint.map((endpoint) => {
        if (typeof endpoint === 'string') {
          try {
            const parsed = JSON.parse(endpoint);
            // Ensure the parsed object has the expected structure
            return {
              uri: parsed.uri || endpoint,
              accept: parsed.accept || [],
              routingKeys: parsed.routingKeys || [],
              recipientKeys: parsed.recipientKeys || [],
              priority: parsed.priority || 0,
            };
          } catch (error) {
            return { uri: endpoint, accept: [], routingKeys: [] };
          }
        } else if (endpoint && typeof endpoint === 'object') {
          // Already an object, ensure it has the expected structure
          return {
            uri: endpoint.uri || '',
            accept: endpoint.accept || [],
            routingKeys: endpoint.routingKeys || [],
            recipientKeys: endpoint.recipientKeys || [],
            priority: endpoint.priority || 0,
          };
        } else {
          return { uri: String(endpoint), accept: [], routingKeys: [] };
        }
      });
    }

    return result;
  }

  toCheqdPayload() {
    const result = {
      id: this.id.toJSON(),
      serviceType: this.serviceType.toJSON(),
      serviceEndpoint: this.serviceEndpoint.toJSON(),
    };

    // For DIDComm services, provide the flattened structure expected by downstream
    if (this.serviceType instanceof DIDCommMessaging) {
      const uris = [];
      const accepts = [];
      const routingKeys = [];
      const recipientKeys = [];

      result.serviceEndpoint.forEach((endpoint) => {
        if (typeof endpoint === 'string') {
          try {
            const parsed = JSON.parse(endpoint);
            uris.push(parsed.uri);
            accepts.push(...(parsed.accept || []));
            routingKeys.push(...(parsed.routingKeys || []));
            recipientKeys.push(...(parsed.recipientKeys || []));
          } catch {
            uris.push(endpoint);
          }
        } else if (endpoint && typeof endpoint === 'object') {
          // Handle structured object directly
          uris.push(endpoint.uri || '');
          accepts.push(...(endpoint.accept || []));
          routingKeys.push(...(endpoint.routingKeys || []));
          recipientKeys.push(...(endpoint.recipientKeys || []));
        } else {
          uris.push(endpoint);
        }
      });

      // Return the flattened structure expected by downstream
      return {
        id: result.id,
        serviceType: result.serviceType,
        serviceEndpoint: uris,
        accept: accepts,
        routingKeys,
        recipientKeys,
        priority: 0, // Default priority
      };
    }

    return result;
  }
}

class CheqdTestnetService extends types_generic_withProp(
  CheqdService,
  'id',
  CheqdTestnetServiceEndpointId,
) {}
class CheqdMainnetService extends types_generic_withProp(
  CheqdService,
  'id',
  CheqdMainnetServiceEndpointId,
) {}

class ServiceEndpoints extends types_generic_typedMap {
  static KeyClass = ServiceEndpointId;

  static ValueClass = ServiceEndpoint;
}

exports.CheqdMainnetService = CheqdMainnetService;
exports.CheqdMainnetServiceEndpointId = CheqdMainnetServiceEndpointId;
exports.CheqdService = CheqdService;
exports.CheqdServiceEndpointId = CheqdServiceEndpointId;
exports.CheqdTestnetService = CheqdTestnetService;
exports.CheqdTestnetServiceEndpointId = CheqdTestnetServiceEndpointId;
exports.DIDCommMessaging = DIDCommMessaging;
exports.DIDCommService = DIDCommService;
exports.DIDCommServiceEndpoint = DIDCommServiceEndpoint;
exports.DIDCommServiceEndpointValue = DIDCommServiceEndpointValue;
exports.DIDCommServiceEndpoints = DIDCommServiceEndpoints;
exports.DIDCommServiceEndpointsArray = DIDCommServiceEndpointsArray;
exports.LinkedDomains = LinkedDomains;
exports.Service = Service;
exports.ServiceEndpoint = ServiceEndpoint;
exports.ServiceEndpointId = ServiceEndpointId;
exports.ServiceEndpointOrigin = ServiceEndpointOrigin;
exports.ServiceEndpointOrigins = ServiceEndpointOrigins;
exports.ServiceEndpointType = ServiceEndpointType;
exports.ServiceEndpointValue = ServiceEndpointValue;
exports.ServiceEndpoints = ServiceEndpoints;
exports.ServiceEndpointsType = ServiceEndpointsType;
exports.SuffixServiceEndpointId = SuffixServiceEndpointId;
exports.UnknownServiceEndpoint = UnknownServiceEndpoint;
exports.createServiceEndpoint = createServiceEndpoint;
//# sourceMappingURL=service-endpoint.cjs.map
