// Copyright 2019 Google LLC
//
// 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
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// 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.

const AdLanternMetric = require('./ad-lantern-metric');
// @ts-ignore
const ComputedMetric = require('lighthouse/lighthouse-core/computed/metrics/metric');
// @ts-ignore
const makeComputedArtifact = require('lighthouse/lighthouse-core/computed/computed-artifact');
const {getBidStartTime, getPageStartTime} = require('../utils/network-timing');
const {isBidRequest} = require('../utils/resource-classification');

// @ts-ignore
// eslint-disable-next-line max-len
/** @typedef {import('lighthouse/lighthouse-core/lib/dependency-graph/base-node.js').Node} Node */

/** Computes simulated first ad request time using Lantern. */
class LanternBidRequestTime extends AdLanternMetric {
  /**
   * @param {LH.Gatherer.Simulation.Result} simulationResult
   * @param {Object} extras
   * @return {LH.Gatherer.Simulation.Result}
   * @override
   */
  static getEstimateFromSimulation(simulationResult, extras) {
    const {nodeTimings} = simulationResult;
    const timeInMs = AdLanternMetric.findNetworkTiming(
      nodeTimings, isBidRequest).startTime;
    return {timeInMs, nodeTimings};
  }
}

// Decorate the class.
// @ts-ignore Allow reassignment for decoration.
// eslint-disable-next-line no-class-assign
LanternBidRequestTime = makeComputedArtifact(LanternBidRequestTime);

/** Computes time to the first ad request. */
class BidRequestTime extends ComputedMetric {
  /**
   * @param {LH.Artifacts.MetricComputationData} data
   * @param {LH.Audit.Context} context
   * @return {Promise<LH.Artifacts.LanternMetric>}
   * @override
   */
  static async computeSimulatedMetric(data, context) {
    // @ts-ignore request does not exist on LanternBidRequestTime
    return LanternBidRequestTime.request(data, context);
  }

  /**
   * @param {LH.Artifacts.MetricComputationData} data
   * @return {Promise<LH.Artifacts.Metric>}
   * @override
   */
  static async computeObservedMetric(data) {
    const {networkRecords} = data;
    const pageStartTime = getPageStartTime(networkRecords);
    const bidStartTime = getBidStartTime(networkRecords);
    const bidRequestTimeMs = (bidStartTime - pageStartTime) * 1000;
    return Promise.resolve({timing: bidRequestTimeMs});
  }
}

// Decorate the class.
// @ts-ignore Allow reassignment for decoration.
// eslint-disable-next-line no-class-assign
BidRequestTime = makeComputedArtifact(BidRequestTime);

module.exports = BidRequestTime;

@@ -854,16 +854,32 @@
 %0Aconst %7B
+getAdStartTime, 
 getBidSt
@@ -950,16 +950,29 @@
 %0Aconst %7B
+isAdRequest, 
 isBidReq
@@ -1570,17 +1570,20 @@
   const 
-t
+bidT
 imeInMs 
@@ -1671,17 +1671,225 @@
     
-return %7Bt
+const adRequestTimeMs = AdLanternMetric.findNetworkTiming(%0A      nodeTimings, isAdRequest).startTime;%0A    if (bidTimeInMs %3E adRequestTimeMs) %7B%0A      return %7BtimeInMs: -1, nodeTimings%7D;%0A    %7D%0A    return %7BtimeInMs: bidT
 imeI
@@ -2861,32 +2861,159 @@
 etworkRecords);%0A
+    const adStartTime = getAdStartTime(networkRecords);%0A    if (adStartTime %3C bidStartTime) %7B%0A      return %7Btiming: -1%7D;%0A    %7D%0A
     const bidReq
@@ -3079,24 +3079,8 @@
 urn 
-Promise.resolve(
 %7Btim
@@ -3101,17 +3101,16 @@
 tTimeMs%7D
-)
 ;%0A  %7D%0A%7D%0A

Enforce that the bid time metric is less than ad req time (#179)