/*
 * Copyright (C) 2019 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {Transport, VerifiableTransport} from './transport.js';

/**
 * A recursive partial object
 *
 * Copied from https://stackoverflow.com/a/51365037
 */
export type RecursivePartial<T> = {
  [P in keyof T]?: T[P] extends Array<infer U>
    ? Array<RecursivePartial<U>>
    : T[P] extends object
      ? RecursivePartial<T[P]>
      : T[P];
};

/**
 * Deletes all properties that are undefined from an object
 * @param object Object to delete undefined properties from
 */
export function deleteUndefinedProperties(object: unknown): unknown {
  // return atomic data types and arrays (recursion anchor)
  if (typeof object !== 'object' || Array.isArray(object)) {
    return object;
  }

  // check each key
  for (const key in object) {
    /* istanbul ignore if */
    if (!object.hasOwnProperty(key)) {
      continue;
    }

    const indexedObject = object as {[k: string]: unknown};

    if (indexedObject[key] === undefined) {
      // delete undefined keys
      delete indexedObject[key];
    } else {
      // check recursive
      indexedObject[key] = deleteUndefinedProperties(indexedObject[key]);
    }
  }

  return object;
}

/**
 * Checks if environment is Node.js
 */
export function isNodeEnvironment(): boolean {
  return Object.prototype.toString.call(typeof process === 'undefined' ? 0 : process) === '[object process]';
}

/**
 * Checks if environment is productive
 */
export function isProductiveEnvironment(): boolean {
  return (
    typeof process.env === 'object' &&
    process.env.NODE_ENV !== undefined &&
    process.env.NODE_ENV === 'production'
  );
}

/**
 * Checks if environment is Node.js and productive
 */
export function isProductiveNodeEnvironment(): boolean {
  return isNodeEnvironment() && isProductiveEnvironment();
}

/**
 * Check if a transport is a verifiable transport
 * @param transport Transport to check
 */
export function isTransportWithVerification(transport: Transport): transport is VerifiableTransport {
  return transport instanceof VerifiableTransport;
}
