/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 * <p>http://www.apache.org/licenses/LICENSE-2.0
 *
 * <p>Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.vts.util;


import com.android.vts.entity.ApiCoverageEntity;
import com.android.vts.entity.BranchEntity;
import com.android.vts.entity.BuildTargetEntity;
import com.android.vts.entity.CodeCoverageEntity;
import com.android.vts.entity.CoverageEntity;
import com.android.vts.entity.DeviceInfoEntity;
import com.android.vts.entity.ProfilingPointRunEntity;
import com.android.vts.entity.TestCaseRunEntity;
import com.android.vts.entity.TestEntity;
import com.android.vts.entity.TestPlanEntity;
import com.android.vts.entity.TestPlanRunEntity;
import com.android.vts.entity.TestRunEntity;
import com.android.vts.entity.TestRunEntity.TestRunType;
import com.android.vts.job.VtsAlertJobServlet;
import com.android.vts.job.VtsCoverageAlertJobServlet;
import com.android.vts.job.VtsProfilingStatsJobServlet;
import com.android.vts.proto.VtsReportMessage.AndroidDeviceInfoMessage;
import com.android.vts.proto.VtsReportMessage.ApiCoverageReportMessage;
import com.android.vts.proto.VtsReportMessage.CoverageReportMessage;
import com.android.vts.proto.VtsReportMessage.HalInterfaceMessage;
import com.android.vts.proto.VtsReportMessage.LogMessage;
import com.android.vts.proto.VtsReportMessage.ProfilingReportMessage;
import com.android.vts.proto.VtsReportMessage.TestCaseReportMessage;
import com.android.vts.proto.VtsReportMessage.TestCaseResult;
import com.android.vts.proto.VtsReportMessage.TestPlanReportMessage;
import com.android.vts.proto.VtsReportMessage.TestReportMessage;
import com.android.vts.proto.VtsReportMessage.UrlResourceMessage;
import com.google.appengine.api.datastore.DatastoreFailureException;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.DatastoreTimeoutException;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.datastore.TransactionOptions;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * DatastoreHelper, a helper class for interacting with Cloud Datastore.
 */
public class DatastoreHelper {

  /**
   * The default kind name for datastore
   */
  public static final String NULL_ENTITY_KIND = "nullEntity";

  public static final int MAX_WRITE_RETRIES = 5;
  /**
   * This variable is for maximum number of entities per transaction You can find the detail here
   * (https://cloud.google.com/datastore/docs/concepts/limits)
   */
  public static final int MAX_ENTITY_SIZE_PER_TRANSACTION = 300;

  protected static final Logger logger = Logger.getLogger(DatastoreHelper.class.getName());
  private static final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

  /**
   * Get query fetch options for large batches of entities.
   *
   * @return FetchOptions with a large chunk and prefetch size.
   */
  public static FetchOptions getLargeBatchOptions() {
    return FetchOptions.Builder.withChunkSize(1000).prefetchSize(1000);
  }

  /**
   * Returns true if there are data points newer than lowerBound in the results table.
   *
   * @param parentKey The parent key to use in the query.
   * @param kind The query entity kind.
   * @param lowerBound The (exclusive) lower time bound, long, microseconds.
   * @return boolean True if there are newer data points.
   */
  public static boolean hasNewer(Key parentKey, String kind, Long lowerBound) {
    if (lowerBound == null || lowerBound <= 0) {
      return false;
    }
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    Key startKey = KeyFactory.createKey(parentKey, kind, lowerBound);
    Filter startFilter =
            new FilterPredicate(
                    Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, startKey);
    Query q = new Query(kind).setAncestor(parentKey).setFilter(startFilter).setKeysOnly();
    return datastore.prepare(q).countEntities(FetchOptions.Builder.withLimit(1)) > 0;
  }

  /**
   * Returns true if there are data points older than upperBound in the table.
   *
   * @param parentKey The parent key to use in the query.
   * @param kind The query entity kind.
   * @param upperBound The (exclusive) upper time bound, long, microseconds.
   * @return boolean True if there are older data points.
   */
  public static boolean hasOlder(Key parentKey, String kind, Long upperBound) {
    if (upperBound == null || upperBound <= 0) {
      return false;
    }
    Key endKey = KeyFactory.createKey(parentKey, kind, upperBound);
    Filter endFilter =
            new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.LESS_THAN, endKey);
    Query q = new Query(kind).setAncestor(parentKey).setFilter(endFilter).setKeysOnly();
    return datastore.prepare(q).countEntities(FetchOptions.Builder.withLimit(1)) > 0;
  }

  /**
   * Get all of the devices branches.
   *
   * @return a list of all branches.
   */
  public static List<String> getAllBranches() {
    Query query = new Query(BranchEntity.KIND).setKeysOnly();
    List<String> branches = new ArrayList<>();
    for (Entity e : datastore.prepare(query).asIterable(getLargeBatchOptions())) {
      branches.add(e.getKey().getName());
    }
    return branches;
  }

  /**
   * Get all of the device build flavors.
   *
   * @return a list of all device build flavors.
   */
  public static List<String> getAllBuildFlavors() {
    Query query = new Query(BuildTargetEntity.KIND).setKeysOnly();
    List<String> devices = new ArrayList<>();
    for (Entity e : datastore.prepare(query).asIterable(getLargeBatchOptions())) {
      devices.add(e.getKey().getName());
    }
    return devices;
  }

  /**
   * Upload data from a test report message
   *
   * @param report The test report containing data to upload.
   */
  public static void insertTestReport(TestReportMessage report) {

    List<Entity> testEntityList = new ArrayList<>();
    List<Entity> branchEntityList = new ArrayList<>();
    List<Entity> buildTargetEntityList = new ArrayList<>();
    List<Entity> coverageEntityList = new ArrayList<>();
    List<Entity> profilingPointRunEntityList = new ArrayList<>();

    if (!report.hasStartTimestamp()
            || !report.hasEndTimestamp()
            || !report.hasTest()
            || !report.hasHostInfo()
            || !report.hasBuildInfo()) {
      // missing information
      return;
    }
    long startTimestamp = report.getStartTimestamp();
    long endTimestamp = report.getEndTimestamp();
    String testName = report.getTest().toStringUtf8();
    String testBuildId = report.getBuildInfo().getId().toStringUtf8();
    String hostName = report.getHostInfo().getHostname().toStringUtf8();

    TestEntity testEntity = new TestEntity(testName);

    Key testRunKey =
            KeyFactory.createKey(
                    testEntity.getOldKey(), TestRunEntity.KIND, report.getStartTimestamp());

    long passCount = 0;
    long failCount = 0;
    long coveredLineCount = 0;
    long totalLineCount = 0;

    Set<Key> buildTargetKeys = new HashSet<>();
    Set<Key> branchKeys = new HashSet<>();
    List<TestCaseRunEntity> testCases = new ArrayList<>();
    List<Key> profilingPointKeys = new ArrayList<>();
    List<String> links = new ArrayList<>();

    // Process test cases
    for (TestCaseReportMessage testCase : report.getTestCaseList()) {
      String testCaseName = testCase.getName().toStringUtf8();
      TestCaseResult result = testCase.getTestResult();
      // Track global pass/fail counts
      if (result == TestCaseResult.TEST_CASE_RESULT_PASS) {
        ++passCount;
      } else if (result != TestCaseResult.TEST_CASE_RESULT_SKIP) {
        ++failCount;
      }
      if (testCase.getSystraceCount() > 0
              && testCase.getSystraceList().get(0).getUrlCount() > 0) {
        String systraceLink = testCase.getSystraceList().get(0).getUrl(0).toStringUtf8();
        links.add(systraceLink);
      }

      // Process coverage data for test case
      for (CoverageReportMessage coverage : testCase.getCoverageList()) {
        CoverageEntity coverageEntity =
                CoverageEntity.fromCoverageReport(testRunKey, testCaseName, coverage);
        if (coverageEntity == null) {
          logger.log(Level.WARNING, "Invalid coverage report in test run " + testRunKey);
        } else {
          coveredLineCount += coverageEntity.getCoveredCount();
          totalLineCount += coverageEntity.getTotalCount();
          coverageEntityList.add(coverageEntity.toEntity());
        }
      }

      // Process profiling data for test case
      for (ProfilingReportMessage profiling : testCase.getProfilingList()) {
        ProfilingPointRunEntity profilingPointRunEntity =
                ProfilingPointRunEntity.fromProfilingReport(testRunKey, profiling);
        if (profilingPointRunEntity == null) {
          logger.log(Level.WARNING, "Invalid profiling report in test run " + testRunKey);
        } else {
          profilingPointRunEntityList.add(profilingPointRunEntity.toEntity());
          profilingPointKeys.add(profilingPointRunEntity.getKey());
          testEntity.setHasProfilingData(true);
        }
      }

      int lastIndex = testCases.size() - 1;
      if (lastIndex < 0 || testCases.get(lastIndex).isFull()) {
        testCases.add(new TestCaseRunEntity());
        ++lastIndex;
      }
      TestCaseRunEntity testCaseEntity = testCases.get(lastIndex);
      testCaseEntity.addTestCase(testCaseName, result.getNumber());
    }

    List<Entity> testCasePuts = new ArrayList<>();
    for (TestCaseRunEntity testCaseEntity : testCases) {
      testCasePuts.add(testCaseEntity.toEntity());
    }
    List<Key> testCaseKeys = datastore.put(testCasePuts);

    List<Long> testCaseIds = new ArrayList<>();
    for (Key key : testCaseKeys) {
      testCaseIds.add(key.getId());
    }

    // Process device information
    long testRunType = 0;
    for (AndroidDeviceInfoMessage device : report.getDeviceInfoList()) {
      DeviceInfoEntity deviceInfoEntity =
              DeviceInfoEntity.fromDeviceInfoMessage(testRunKey, device);
      if (deviceInfoEntity == null) {
        logger.log(Level.WARNING, "Invalid device info in test run " + testRunKey);
      } else {
        // Run type on devices must be the same, else set to OTHER
        TestRunType runType = TestRunType.fromBuildId(deviceInfoEntity.getBuildId());
        if (runType == null) {
          testRunType = TestRunType.OTHER.getNumber();
        } else {
          testRunType = runType.getNumber();
        }
        testEntityList.add(deviceInfoEntity.toEntity());
        BuildTargetEntity target = new BuildTargetEntity(deviceInfoEntity.getBuildFlavor());
        if (buildTargetKeys.add(target.key)) {
          buildTargetEntityList.add(target.toEntity());
        }
        BranchEntity branch = new BranchEntity(deviceInfoEntity.getBranch());
        if (branchKeys.add(branch.key)) {
          branchEntityList.add(branch.toEntity());
        }
      }
    }

    // Overall run type should be determined by the device builds unless test build is OTHER
    if (testRunType == TestRunType.OTHER.getNumber()) {
      testRunType = TestRunType.fromBuildId(testBuildId).getNumber();
    } else if (TestRunType.fromBuildId(testBuildId) == TestRunType.OTHER) {
      testRunType = TestRunType.OTHER.getNumber();
    }

    // Process global coverage data
    for (CoverageReportMessage coverage : report.getCoverageList()) {
      CoverageEntity coverageEntity =
              CoverageEntity.fromCoverageReport(testRunKey, new String(), coverage);
      if (coverageEntity == null) {
        logger.log(Level.WARNING, "Invalid coverage report in test run " + testRunKey);
      } else {
        coveredLineCount += coverageEntity.getCoveredCount();
        totalLineCount += coverageEntity.getTotalCount();
        coverageEntityList.add(coverageEntity.toEntity());
      }
    }

    // Process global API coverage data
    for (ApiCoverageReportMessage apiCoverage : report.getApiCoverageList()) {
      HalInterfaceMessage halInterfaceMessage = apiCoverage.getHalInterface();
      List<String> halApiList = apiCoverage.getHalApiList().stream().map(h -> h.toStringUtf8())
              .collect(
                      Collectors.toList());
      List<String> coveredHalApiList = apiCoverage.getCoveredHalApiList().stream()
              .map(h -> h.toStringUtf8()).collect(
                      Collectors.toList());
      ApiCoverageEntity apiCoverageEntity = new ApiCoverageEntity(
              testRunKey,
              halInterfaceMessage.getHalPackageName().toStringUtf8(),
              halInterfaceMessage.getHalVersionMajor(),
              halInterfaceMessage.getHalVersionMinor(),
              halInterfaceMessage.getHalInterfaceName().toStringUtf8(),
              halApiList,
              coveredHalApiList
      );
      com.googlecode.objectify.Key apiCoverageEntityKey = apiCoverageEntity.save();
      if (apiCoverageEntityKey == null) {
        logger.log(Level.WARNING, "Invalid API coverage report in test run " + testRunKey);
      }
    }

    // Process global profiling data
    for (ProfilingReportMessage profiling : report.getProfilingList()) {
      ProfilingPointRunEntity profilingPointRunEntity =
              ProfilingPointRunEntity.fromProfilingReport(testRunKey, profiling);
      if (profilingPointRunEntity == null) {
        logger.log(Level.WARNING, "Invalid profiling report in test run " + testRunKey);
      } else {
        profilingPointRunEntityList.add(profilingPointRunEntity.toEntity());
        profilingPointKeys.add(profilingPointRunEntity.getKey());
        testEntity.setHasProfilingData(true);
      }
    }

    // Process log data
    for (LogMessage log : report.getLogList()) {
      if (log.hasUrl()) {
        links.add(log.getUrl().toStringUtf8());
      }
    }
    // Process url resource
    for (UrlResourceMessage resource : report.getLinkResourceList()) {
      if (resource.hasUrl()) {
        links.add(resource.getUrl().toStringUtf8());
      }
    }

    boolean hasCodeCoverage = totalLineCount > 0 && coveredLineCount >= 0;
    TestRunEntity testRunEntity =
            new TestRunEntity(
                    testEntity.getOldKey(),
                    testRunType,
                    startTimestamp,
                    endTimestamp,
                    testBuildId,
                    hostName,
                    passCount,
                    failCount,
                    hasCodeCoverage,
                    testCaseIds,
                    links);
    testEntityList.add(testRunEntity.toEntity());

    CodeCoverageEntity codeCoverageEntity = new CodeCoverageEntity(
            testRunEntity.getKey(),
            coveredLineCount,
            totalLineCount);
    testEntityList.add(codeCoverageEntity.toEntity());

    Entity test = testEntity.toEntity();

    if (datastoreTransactionalRetry(test, testEntityList)) {
      List<List<Entity>> auxiliaryEntityList =
              Arrays.asList(
                      profilingPointRunEntityList,
                      coverageEntityList,
                      branchEntityList,
                      buildTargetEntityList);
      int indexCount = 0;
      for (List<Entity> entityList : auxiliaryEntityList) {
        switch (indexCount) {
          case 0:
          case 1:
            if (entityList.size() > MAX_ENTITY_SIZE_PER_TRANSACTION) {
              List<List<Entity>> partitionedList =
                      Lists.partition(entityList, MAX_ENTITY_SIZE_PER_TRANSACTION);
              partitionedList.forEach(
                      subEntityList -> {
                        datastoreTransactionalRetry(
                                new Entity(NULL_ENTITY_KIND), subEntityList);
                      });
            } else {
              datastoreTransactionalRetry(new Entity(NULL_ENTITY_KIND), entityList);
            }
            break;
          case 2:
          case 3:
            datastoreTransactionalRetryWithXG(
                    new Entity(NULL_ENTITY_KIND), entityList, true);
            break;
          default:
            break;
        }
        indexCount++;
      }

      if (testRunEntity.getType() == TestRunType.POSTSUBMIT.getNumber()) {
        VtsAlertJobServlet.addTask(testRunKey);
        if (testRunEntity.getHasCodeCoverage()) {
          VtsCoverageAlertJobServlet.addTask(testRunKey);
        }
        if (profilingPointKeys.size() > 0) {
          VtsProfilingStatsJobServlet.addTasks(profilingPointKeys);
        }
      } else {
        logger.log(
                Level.WARNING,
                "The alert email was not sent as testRunEntity type is not POSTSUBMIT!" +
                        " \n " + " testRunEntity type => " + testRunEntity.getType());
      }
    }
  }

  /**
   * Upload data from a test plan report message
   *
   * @param report The test plan report containing data to upload.
   */
  public static void insertTestPlanReport(TestPlanReportMessage report) {
    List<Entity> testEntityList = new ArrayList<>();

    List<String> testModules = report.getTestModuleNameList();
    List<Long> testTimes = report.getTestModuleStartTimestampList();
    if (testModules.size() != testTimes.size() || !report.hasTestPlanName()) {
      logger.log(Level.WARNING, "TestPlanReportMessage is missing information.");
      return;
    }

    String testPlanName = report.getTestPlanName();
    Entity testPlanEntity = new TestPlanEntity(testPlanName).toEntity();
    List<Key> testRunKeys = new ArrayList<>();
    for (int i = 0; i < testModules.size(); i++) {
      String test = testModules.get(i);
      long time = testTimes.get(i);
      Key parentKey = KeyFactory.createKey(TestEntity.KIND, test);
      Key testRunKey = KeyFactory.createKey(parentKey, TestRunEntity.KIND, time);
      testRunKeys.add(testRunKey);
    }
    Map<Key, Entity> testRuns = datastore.get(testRunKeys);
    long passCount = 0;
    long failCount = 0;
    long startTimestamp = -1;
    long endTimestamp = -1;
    String testBuildId = null;
    long type = 0;
    Set<DeviceInfoEntity> deviceInfoEntitySet = new HashSet<>();
    for (Key testRunKey : testRuns.keySet()) {
      TestRunEntity testRun = TestRunEntity.fromEntity(testRuns.get(testRunKey));
      if (testRun == null) {
        continue; // not a valid test run
      }
      passCount += testRun.getPassCount();
      failCount += testRun.getFailCount();
      if (startTimestamp < 0 || testRunKey.getId() < startTimestamp) {
        startTimestamp = testRunKey.getId();
      }
      if (endTimestamp < 0 || testRun.getEndTimestamp() > endTimestamp) {
        endTimestamp = testRun.getEndTimestamp();
      }
      type = testRun.getType();
      testBuildId = testRun.getTestBuildId();
      Query deviceInfoQuery = new Query(DeviceInfoEntity.KIND).setAncestor(testRunKey);
      for (Entity deviceInfoEntity : datastore.prepare(deviceInfoQuery).asIterable()) {
        DeviceInfoEntity device = DeviceInfoEntity.fromEntity(deviceInfoEntity);
        if (device == null) {
          continue; // invalid entity
        }
        deviceInfoEntitySet.add(device);
      }
    }
    if (startTimestamp < 0 || testBuildId == null || type == 0) {
      logger.log(Level.WARNING, "Couldn't infer test run information from runs.");
      return;
    }
    TestPlanRunEntity testPlanRun =
            new TestPlanRunEntity(
                    testPlanEntity.getKey(),
                    testPlanName,
                    type,
                    startTimestamp,
                    endTimestamp,
                    testBuildId,
                    passCount,
                    failCount,
                    0L,
                    0L,
                    testRunKeys);

    // Create the device infos.
    for (DeviceInfoEntity device : deviceInfoEntitySet) {
      testEntityList.add(device.copyWithParent(testPlanRun.key).toEntity());
    }
    testEntityList.add(testPlanRun.toEntity());

    // Add the task to calculate total number API list.
    testPlanRun.addCoverageApiTask();

    datastoreTransactionalRetry(testPlanEntity, testEntityList);
  }

  /**
   * Datastore Transactional process for data insertion with MAX_WRITE_RETRIES times and withXG of
   * false value
   *
   * @param entity The entity that you want to insert to datastore.
   * @param entityList The list of entity for using datastore put method.
   */
  private static boolean datastoreTransactionalRetry(Entity entity, List<Entity> entityList) {
    return datastoreTransactionalRetryWithXG(entity, entityList, false);
  }

  /**
   * Datastore Transactional process for data insertion with MAX_WRITE_RETRIES times
   *
   * @param entity The entity that you want to insert to datastore.
   * @param entityList The list of entity for using datastore put method.
   */
  private static boolean datastoreTransactionalRetryWithXG(
          Entity entity, List<Entity> entityList, boolean withXG) {
    int retries = 0;
    while (true) {
      Transaction txn;
      if (withXG) {
        TransactionOptions options = TransactionOptions.Builder.withXG(withXG);
        txn = datastore.beginTransaction(options);
      } else {
        txn = datastore.beginTransaction();
      }

      try {
        // Check if test already exists in the database
        if (!entity.getKind().equalsIgnoreCase(NULL_ENTITY_KIND)) {
          try {
            if (entity.getKind().equalsIgnoreCase("Test")) {
              Entity datastoreEntity = datastore.get(entity.getKey());
              TestEntity datastoreTestEntity = TestEntity.fromEntity(datastoreEntity);
              if (datastoreTestEntity == null
                      || !datastoreTestEntity.equals(entity)) {
                entityList.add(entity);
              }
            } else if (entity.getKind().equalsIgnoreCase("TestPlan")) {
              datastore.get(entity.getKey());
            } else {
              datastore.get(entity.getKey());
            }
          } catch (EntityNotFoundException e) {
            entityList.add(entity);
          }
        }
        datastore.put(txn, entityList);
        txn.commit();
        break;
      } catch (ConcurrentModificationException
              | DatastoreFailureException
              | DatastoreTimeoutException e) {
        entityList.remove(entity);
        logger.log(
                Level.WARNING,
                "Retrying insert kind: " + entity.getKind() + " key: " + entity.getKey());
        if (retries++ >= MAX_WRITE_RETRIES) {
          logger.log(
                  Level.SEVERE,
                  "Exceeded maximum retries kind: "
                          + entity.getKind()
                          + " key: "
                          + entity.getKey());
          return false;
        }
      } finally {
        if (txn.isActive()) {
          logger.log(
                  Level.WARNING, "Transaction rollback forced for : " + entity.getKind());
          txn.rollback();
        }
      }
    }
    return true;
  }
}
