/**
   * Track dsa bids performance
   *
   * @throws Exception
   */
  public void start(IDsaTrackerUserConfiguration userConfig) throws Exception {
    Map<String, Account> accounts = sourceManager.loadSources(userConfig);

    Map<Long, AdGroupPerformance> baseReport = initializeBaseReport(userConfig, accounts);
    Map<Long, AdGroupPerformance> report = baseReport;
    do {
      modifyBids(userConfig, accounts, baseReport, report);

      // update adGroups bids
      if (!userConfig.getIdleMode()) {
        adGroupBidUploaderService.uploadBids(
            userConfig,
            accounts
                .values()
                .stream()
                .flatMap(accountData -> accountData.getCampaigns().values().stream())
                .flatMap(campaignData -> campaignData.getAdGroups().values().stream()));
      }

      if (configuration.dsaTracker.singleRunMod) {
        return;
      }

      LOGGER.info(
          "Wait for data to accumulate (waitTime = "
              + userConfig.getDsaTracker().waitTime
              + " sec)...");
      Thread.sleep(userConfig.getDsaTracker().waitTime * 1000);

      LocalDateTime dateOne = now();
      LocalDateTime dateTwo = dateOne.minusDays(REPORT_DAYS);
      report =
          performanceDataLoader.downloadPerformanceData(
              accounts, dateTwo.toLocalDate(), dateOne.toLocalDate());
    } while (!Thread.interrupted());
  }
  private Map<Long, AdGroupPerformance> initializeBaseReport(
      IDsaTrackerUserConfiguration userConfig, final Map<String, Account> accounts)
      throws Exception {
    if (userConfig.getDsaTracker().reinitializeBaseReport) {
      File baseReportFile = fsUtils.getResultFile(userConfig, "DsaBaseReport");
      LOGGER.info("Reinitialize base report");

      // update adGroups bids
      if (!userConfig.getIdleMode()) {
        adGroupBidUploaderService.uploadBids(
            userConfig,
            accounts
                .values()
                .stream()
                .flatMap(accountData -> accountData.getCampaigns().values().stream())
                .flatMap(campaignData -> campaignData.getAdGroups().values().stream()));
      }

      if (!configuration.dsaTracker.singleRunMod) {
        LOGGER.info(
            "Wait for data to accumulate (waitTime = "
                + userConfig.getDsaTracker().waitTime
                + " sec)...");
        Thread.sleep(userConfig.getDsaTracker().waitTime * 1000);
      }

      LocalDateTime dateOne = now();
      LocalDateTime dateTwo = dateOne.minusDays(REPORT_DAYS);
      Map<Long, AdGroupPerformance> baseReport =
          performanceDataLoader.downloadPerformanceData(
              accounts, dateTwo.toLocalDate(), dateOne.toLocalDate());

      for (Long key : baseReport.keySet()) {
        if (baseReport.get(key).adGroup == null) baseReport.remove(key);
      }

      for (Account account : accounts.values()) {
        for (Campaign campaign : account.getCampaigns().values()) {
          for (AdGroup adGroup : campaign.getAdGroups().values()) {
            if (baseReport.get(adGroup.getAdGroupId()) != null) continue;
            AdGroupPerformance adGroupPerformance = new AdGroupPerformance();
            Long campaignId = campaign.getCampaignId();
            Long adGroupId = adGroup.getAdGroupId();
            adGroupPerformance.adGroup =
                new AdGroupImpl(
                    new CampaignImpl(new AccountImpl(account.getAccountId()), campaignId),
                    adGroupId);
            adGroupPerformance.adGroup.setMetrics(
                new DsaMetrics() {
                  {
                    setMaxBid(0.0);
                  }
                });
            adGroupPerformance.hasConversions = false;
            adGroupPerformance.averageCpc = 0;
            adGroupPerformance.averagePosition = 0;
            adGroupPerformance.clicks = 0;
            adGroupPerformance.cost = 0;
            adGroupPerformance.impressions = 0;

            baseReport.put(adGroupId, adGroupPerformance);
          }
        }
      }

      baseReport
          .values()
          .forEach(
              r -> {
                DsaMetrics metrics = (DsaMetrics) r.adGroup.getMetrics();
                r.maxBaseCpc =
                    metrics.getMaxBid() * (1 + userConfig.getDsaTracker().maxCpcBidChange);
                r.minBaseCpc =
                    metrics.getMaxBid() * (1 - userConfig.getDsaTracker().maxCpcBidChange);
              });

      dsaTrackerUtils.saveBaseReport(baseReportFile, baseReport);
      ((DsaTrackerUserConfiguration) userConfig).baseReportFilePath =
          baseReportFile.getAbsolutePath();

      return baseReport;
    } else {
      LOGGER.info("Load base report from previous launch");
      File baseReportFile = new File(((DsaTrackerUserConfiguration) userConfig).baseReportFilePath);
      if (!baseReportFile.exists()) {
        throw new FileNotFoundException("Basic landscape report file does not exist");
      }

      return dsaTrackerUtils.loadBaseReport(baseReportFile, accounts);
    }
  }