public function uploadFile($data)
    {
        $uploadedFilePromise = $this->getClosestUploadEndpoint()
            ->then(
                function () use ($data) {
                    return $this->requestUploadInformationAsync($data['filePath']);
                })
            ->then(
                function ($uploadRequestInfo) use ($data) {
                    if ($file = fopen($data['filePath'], 'rb')) {

                        $fileSize = filesize($data['filePath']);

                        $numberOfChunks = round(($fileSize + self::CHUNK_SIZE - 1) / self::CHUNK_SIZE);
                        $chunkNumber = 0;

                        // This is where the magic happens. We create all the promises via an Iterator function.
                        $promises = $this->uploadChunkIterator($file, $data['filePath'], $uploadRequestInfo,
                            $numberOfChunks, $chunkNumber);
                        // After that we batch them all together using each_limit_all, which will guarantee all chunks have been uploaded properly.
                        $eachPromises = Promise\each_limit_all($promises, self::MAX_CONCURRENT_CHUNKS);
                        return $eachPromises->then(
                            function ($value) use ($uploadRequestInfo, $chunkNumber) {
                                return ['requestInfo' => $uploadRequestInfo, 'chunkNumber' => $chunkNumber];
                            });
                    } else {
                        throw new Exception("File not Found");
                    }
                }
            )
            ->then(
                function ($value) {
                    return $this->finalizeUploadAsync($value['requestInfo'], $value['chunkNumber']);
                }
            )
            ->then(
                function ($finalizeResponse) {
                    return $this->hasFinishedSuccessfullyAsync($finalizeResponse)
                        ->then(
                            function ($response) use ($finalizeResponse) {
                                return [
                                    'pollStatus' => $response,
                                    'finalizeData' => $finalizeResponse
                                ];
                            });
                }
            )
            ->then(
                function ($value) use ($data) {
                    if ($value['pollStatus'] != false) {
                        $data['importId'] = $value['finalizeData']['importId'];
                        return $this->saveMediaAsync($data);
                    } else {
                        throw new Exception("Converter did not finish. Upload failed.");
                    }
                }
            );

        return $uploadedFilePromise;
    }