// 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/registry/packed_event_codes.h"

namespace cobalt::local_aggregation {

using logger::EventRecord;
using logger::kInvalidArguments;
using logger::kOK;
using logger::ProjectContext;
using logger::Status;

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

// TODO(pesk): update the EventAggregator's view of a Metric
// or ReportDefinition when appropriate.
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_->MaybeInsertReportConfig(project_context, metric, report);
              if (status != kOK) {
                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_->MaybeInsertReportConfig(project_context, metric, report);
              if (status != kOK) {
                return status;
              }
            } break;
            default:
              continue;
          }
        }
      } break;
      default:
        continue;
    }
  }
  return kOK;
}

// 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) {
  auto* event = event_record.event();
  if (!ValidateEventType(Event::kEventOccurredEvent, *event)) {
    return kInvalidArguments;
  }
  auto* metric = event_record.metric();
  return aggregate_store_->SetActive(metric->customer_id(), metric->project_id(), metric->id(),
                                     report_id, event->event_occurred_event().event_code(),
                                     event->day_index());
}

Status EventAggregator::AddEventCountEvent(uint32_t report_id, const EventRecord& event_record) {
  auto* event = event_record.event();
  if (!ValidateEventType(Event::kEventCountEvent, *event)) {
    return kInvalidArguments;
  }

  auto* metric = event_record.metric();
  const EventCountEvent& event_count_event = event->event_count_event();

  return aggregate_store_->UpdateNumericAggregate(
      metric->customer_id(), metric->project_id(), metric->id(), 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) {
  auto* event = event_record.event();
  if (!ValidateEventType(Event::kElapsedTimeEvent, *event)) {
    return kInvalidArguments;
  }

  auto* metric = event_record.metric();
  const ElapsedTimeEvent& elapsed_time_event = event->elapsed_time_event();

  return aggregate_store_->UpdateNumericAggregate(
      metric->customer_id(), metric->project_id(), metric->id(), 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) {
  auto* event = event_record.event();
  if (!ValidateEventType(Event::kFrameRateEvent, *event)) {
    return kInvalidArguments;
  }
  auto* metric = event_record.metric();
  const FrameRateEvent& frame_rate_event = event->frame_rate_event();

  return aggregate_store_->UpdateNumericAggregate(
      metric->customer_id(), metric->project_id(), metric->id(), 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) {
  auto* event = event_record.event();
  if (!ValidateEventType(Event::kMemoryUsageEvent, *event)) {
    return kInvalidArguments;
  }

  auto* metric = event_record.metric();
  const MemoryUsageEvent& memory_usage_event = event->memory_usage_event();

  return aggregate_store_->UpdateNumericAggregate(
      metric->customer_id(), metric->project_id(), metric->id(), report_id,
      memory_usage_event.component(), config::PackEventCodes(memory_usage_event.event_code()),
      event->day_index(), memory_usage_event.bytes());
}
}  // namespace cobalt::local_aggregation
