// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/local_aggregation/event_aggregator.h"

#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <vector>

#include "src/lib/util/datetime_util.h"
#include "src/lib/util/proto_util.h"
#include "src/lib/util/status_builder.h"
#include "src/public/lib/registry_identifiers.h"
#include "src/registry/packed_event_codes.h"

namespace cobalt::local_aggregation {

using logger::EventRecord;
using logger::ProjectContext;

EventAggregator::EventAggregator(AggregateStore& aggregate_store)
    : aggregate_store_(aggregate_store) {}

Status EventAggregator::UpdateAggregationConfigs(const ProjectContext& project_context) {
  Status status;
  for (const auto& metric : project_context.metrics()) {
    switch (metric.metric_type()) {
      case MetricDefinition::EVENT_OCCURRED: {
        for (const auto& report : metric.reports()) {
          switch (report.report_type()) {
            case ReportDefinition::UNIQUE_N_DAY_ACTIVES: {
              status =
                  aggregate_store_.get().MaybeInsertReportConfig(project_context, metric, report);
              if (!status.ok()) {
                return status;
              }
            } break;
            default:
              continue;
          }
        }
      } break;
      case MetricDefinition::EVENT_COUNT:
      case MetricDefinition::ELAPSED_TIME:
      case MetricDefinition::FRAME_RATE:
      case MetricDefinition::MEMORY_USAGE: {
        for (const auto& report : metric.reports()) {
          switch (report.report_type()) {
            case ReportDefinition::PER_DEVICE_NUMERIC_STATS:
            case ReportDefinition::PER_DEVICE_HISTOGRAM: {
              status =
                  aggregate_store_.get().MaybeInsertReportConfig(project_context, metric, report);
              if (!status.ok()) {
                return status;
              }
            } break;
            default:
              continue;
          }
        }
      } break;
      default:
        continue;
    }
  }
  return Status::OkStatus();
}

// Helper functions for the Log*Event() methods.
namespace {

// Checks that an Event has type |expected_event_type|.
bool ValidateEventType(Event::TypeCase expected_event_type, const Event& event) {
  Event::TypeCase event_type = event.type_case();
  if (event_type != expected_event_type) {
    LOG(ERROR) << "Expected Event type is " << expected_event_type << "; found " << event_type
               << ".";
    return false;
  }
  return true;
}

}  // namespace

Status EventAggregator::AddUniqueActivesEvent(uint32_t report_id, const EventRecord& event_record) {
  Event* event = event_record.event();
  if (!ValidateEventType(Event::kEventOccurredEvent, *event)) {
    return util::StatusBuilder(StatusCode::INVALID_ARGUMENT, "Failed to validate arguments")
        .WithContext("ReportId", report_id)
        .WithContexts(event_record)
        .Build();
  }
  return aggregate_store_.get().SetActive(event_record.MetricIdentifier().ForReport(report_id),
                                          event->event_occurred_event().event_code(),
                                          event->day_index());
}

Status EventAggregator::AddEventCountEvent(uint32_t report_id, const EventRecord& event_record) {
  Event* event = event_record.event();
  if (!ValidateEventType(Event::kEventCountEvent, *event)) {
    return util::StatusBuilder(StatusCode::INVALID_ARGUMENT, "Failed to validate arguments")
        .WithContext("ReportId", report_id)
        .WithContexts(event_record)
        .Build();
  }

  const EventCountEvent& event_count_event = event->event_count_event();

  return aggregate_store_.get().UpdateNumericAggregate(
      event_record.MetricIdentifier().ForReport(report_id), event_count_event.component(),
      config::PackEventCodes(event_count_event.event_code()), event->day_index(),
      event_count_event.count());
}

Status EventAggregator::AddElapsedTimeEvent(uint32_t report_id, const EventRecord& event_record) {
  Event* event = event_record.event();
  if (!ValidateEventType(Event::kElapsedTimeEvent, *event)) {
    return util::StatusBuilder(StatusCode::INVALID_ARGUMENT, "Failed to validate arguments")
        .WithContext("ReportId", report_id)
        .WithContexts(event_record)
        .Build();
  }

  const ElapsedTimeEvent& elapsed_time_event = event->elapsed_time_event();

  return aggregate_store_.get().UpdateNumericAggregate(
      event_record.MetricIdentifier().ForReport(report_id), elapsed_time_event.component(),
      config::PackEventCodes(elapsed_time_event.event_code()), event->day_index(),
      elapsed_time_event.elapsed_micros());
}

Status EventAggregator::AddFrameRateEvent(uint32_t report_id, const EventRecord& event_record) {
  Event* event = event_record.event();
  if (!ValidateEventType(Event::kFrameRateEvent, *event)) {
    return util::StatusBuilder(StatusCode::INVALID_ARGUMENT, "Failed to validate arguments")
        .WithContext("ReportId", report_id)
        .WithContexts(event_record)
        .Build();
  }
  const FrameRateEvent& frame_rate_event = event->frame_rate_event();

  return aggregate_store_.get().UpdateNumericAggregate(
      event_record.MetricIdentifier().ForReport(report_id), frame_rate_event.component(),
      config::PackEventCodes(frame_rate_event.event_code()), event->day_index(),
      frame_rate_event.frames_per_1000_seconds());
}

Status EventAggregator::AddMemoryUsageEvent(uint32_t report_id, const EventRecord& event_record) {
  Event* event = event_record.event();
  if (!ValidateEventType(Event::kMemoryUsageEvent, *event)) {
    return util::StatusBuilder(StatusCode::INVALID_ARGUMENT, "Failed to validate arguments")
        .WithContext("ReportId", report_id)
        .WithContexts(event_record)
        .Build();
  }

  const MemoryUsageEvent& memory_usage_event = event->memory_usage_event();

  return aggregate_store_.get().UpdateNumericAggregate(
      event_record.MetricIdentifier().ForReport(report_id), memory_usage_event.component(),
      config::PackEventCodes(memory_usage_event.event_code()), event->day_index(),
      memory_usage_event.bytes());
}
}  // namespace cobalt::local_aggregation
