import { invariant } from '../../invariant';
import { warning } from '../../dev-warning';

interface Version {
  major: number;
  minor: number;
  patch: number;
  raw: string;
}

// We can use a simple regex here given that:
// - the version that react supplies is always full: eg 16.5.2
// - our peer dependency version is to a full version (eg ^16.3.1)
const semver = /(\d+)\.(\d+)\.(\d+)/;
const getVersion = (value: string): Version => {
  const result: string[] | null = semver.exec(value);

  invariant(result != null, `Unable to parse React version ${value}`);

  const major = Number(result[1]);
  const minor = Number(result[2]);
  const patch = Number(result[3]);

  return {
    major,
    minor,
    patch,
    raw: value,
  };
};

const isSatisfied = (expected: Version, actual: Version): boolean => {
  if (actual.major > expected.major) {
    return true;
  }

  if (actual.major < expected.major) {
    return false;
  }

  // major is equal, continue on

  if (actual.minor > expected.minor) {
    return true;
  }

  if (actual.minor < expected.minor) {
    return false;
  }

  // minor is equal, continue on

  return actual.patch >= expected.patch;
};

export default (peerDepValue: string, actualValue: string) => {
  const peerDep: Version = getVersion(peerDepValue);
  const actual: Version = getVersion(actualValue);

  if (isSatisfied(peerDep, actual)) {
    return;
  }

  warning(`
    React version: [${actual.raw}]
    does not satisfy expected peer dependency version: [${peerDep.raw}]

    This can result in run time bugs, and even fatal crashes
  `);
};
