export function parseSemver(version) {
  const match = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version)

  if (!match) {
    throw new Error(`Invalid semver version: ${version}`)
  }

  return {
    major: Number(match[1]),
    minor: Number(match[2]),
    patch: Number(match[3]),
    version: `${match[1]}.${match[2]}.${match[3]}`,
  }
}

export function getReleaseLine(version) {
  const parsed = typeof version === 'string' ? parseSemver(version) : version
  return `${parsed.major}.${parsed.minor}`
}

export function compareSemver(leftVersion, rightVersion) {
  const left = typeof leftVersion === 'string' ? parseSemver(leftVersion) : leftVersion
  const right = typeof rightVersion === 'string' ? parseSemver(rightVersion) : rightVersion

  if (left.major !== right.major) {
    return left.major - right.major
  }

  if (left.minor !== right.minor) {
    return left.minor - right.minor
  }

  return left.patch - right.patch
}

export function findLatestVersionInReleaseLine(packageVersion, versions) {
  const desired = typeof packageVersion === 'string' ? parseSemver(packageVersion) : packageVersion
  const desiredLine = getReleaseLine(desired)

  return versions
    .map(version => parseSemver(version))
    .filter(version => getReleaseLine(version) === desiredLine)
    .sort((left, right) => compareSemver(right, left))[0]?.version ?? null
}

export function resolveReleasePlan(packageVersion, latestTagVersion) {
  const desired = parseSemver(packageVersion)
  const latest = latestTagVersion ? parseSemver(latestTagVersion) : null

  if (!latest) {
    return {
      releaseVersion: desired.version,
      syncedPackageVersion: desired.version,
    }
  }

  if (getReleaseLine(desired) !== getReleaseLine(latest)) {
    return {
      releaseVersion: desired.version,
      syncedPackageVersion: desired.version,
    }
  }

  return {
    releaseVersion: null,
    syncedPackageVersion: latest.version,
  }
}
