type DataTypes = 'CONTENT' | 'PRODUCT' | 'PRODUCT_VARIANT' | 'COLLECTION';
export type SourceName = 'CONTENTFUL' | 'SANITY' | 'SHOPIFY';

interface NacelleEntryIdProperties {
  /**
   * A Nacelle data type
   * @example
   * 'CONTENT'
   */
  dataType: DataTypes;

  /**
   * An IETF locale
   * @example
   * 'en-US'
   */
  locale: string;

  /**
   * A Nacelle source name
   * @example
   * 'CONTENTFUL'
   * @example
   * 'SHOPIFY'
   */
  sourceName: SourceName;

  /**
   * An ID assigned to a piece of data by an upstream system
   * @example
   * 'MTIzNDU2Nzg='
   */
  sourceEntryId: string;

  /**
   * A source environment name
   * @example
   * 'master' (the default production environment name in Contentful)
   * @example
   * 'default' (for systems with no concept of environments, such as Shopify)
   */
  sourceSubset: string;

  /**
   * A source space ID
   * @example
   * '1xqo9yrzp7yz' (a Contentful Space ID)
   * @example
   * 'gamma-nova-jewelry' (a Shopify Shop ID / "subdomain")
   */
  externalId: string;
}

/**
 * Creates a nacelleEntryId for any type of data in Nacelle's indices
 * @param {string} nacelleEntryId a Base64-encoded nacelleEntryId
 * @returns {Object} an object containing all parts of a nacelleEntryId
 */
export function destructureNacelleEntryId(
  nacelleEntryId: string
): NacelleEntryIdProperties {
  const decodedId =
    typeof window === 'undefined'
      ? Buffer.from(nacelleEntryId, 'base64').toString('ascii')
      : self.atob(nacelleEntryId);

  if (!decodedId.startsWith('id://')) {
    throw new Error(
      'Expected a `nacelleEntryId` starting with "id://", received: ' +
        decodedId
    );
  }

  const [, partsOfInterest] = decodedId.split('id://');
  const nacelleEntryIdParts = partsOfInterest.split('/');

  if (nacelleEntryIdParts.length !== 6) {
    throw new Error(
      'Expected nacelleEntryId to contain 6 properties: ' +
        '`sourceName`, `externalId`, `sourceSubset`, `dataType`, ' +
        '`sourceEntryId`, and `locale`. Instead, received:\n' +
        JSON.stringify(
          {
            sourceName: nacelleEntryIdParts[0],
            externalId: nacelleEntryIdParts[1],
            sourceSubset: nacelleEntryIdParts[2],
            dataType: nacelleEntryIdParts[3],
            sourceEntryId: nacelleEntryIdParts[4],
            locale: nacelleEntryIdParts[5]
          },
          null,
          2
        )
    );
  }

  const nacelleEntryIdProperties: NacelleEntryIdProperties = {
    sourceName: nacelleEntryIdParts[0] as SourceName,
    externalId: nacelleEntryIdParts[1],
    sourceSubset: nacelleEntryIdParts[2],
    dataType: nacelleEntryIdParts[3] as DataTypes,
    sourceEntryId: nacelleEntryIdParts[4],
    locale: nacelleEntryIdParts[5]
  };

  return nacelleEntryIdProperties;
}
