/*
 * Copyright (C) 2026 The Android Open Source Project
 *
 * 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.
 */

#ifndef SRC_TRACE_PROCESSOR_TRACE_SUMMARY_SUMMARIZER_H_
#define SRC_TRACE_PROCESSOR_TRACE_SUMMARY_SUMMARIZER_H_

#include <cstdint>
#include <optional>
#include <string>
#include <vector>

#include "perfetto/base/status.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/trace_processor/summarizer.h"

namespace perfetto::trace_processor {

class DescriptorPool;
class TraceProcessor;

namespace perfetto_sql::generator {
class StructuredQueryGenerator;
}  // namespace perfetto_sql::generator

namespace summary {

// Internal implementation of the public Summarizer interface.
// Manages lazy materialization of structured queries.
//
// Key behaviors:
// - Lazy: Queries materialized only when Query() is called.
// - Change detection: Uses proto hash to detect changes.
// - Dependency propagation: If A changes, dependents B->C->D re-materialize.
// - Table substitution: Unchanged queries reference their materialized tables.
// - Cleanup: All materialized tables/views are dropped when the SummarizerImpl
//   is destroyed.
class SummarizerImpl : public Summarizer {
 public:
  SummarizerImpl(TraceProcessor* tp,
                 DescriptorPool* descriptor_pool,
                 std::string id);
  ~SummarizerImpl() override;

  SummarizerImpl(const SummarizerImpl&) = delete;
  SummarizerImpl& operator=(const SummarizerImpl&) = delete;

  // Summarizer implementation.
  base::Status UpdateSpec(const uint8_t* spec_data,
                          size_t spec_size,
                          SummarizerUpdateSpecResult* result) override;

  base::Status Query(const std::string& query_id,
                     SummarizerQueryResult* result) override;

  // Determines whether a query should be created as a VIEW instead of a
  // materialized TABLE. Uses an allowlist of simple pass-through source types;
  // unrecognized or complex sources default to TABLE (safe by default).
  static bool ShouldUseView(const uint8_t* data, size_t size);

 private:
  struct QueryState {
    std::string table_name;
    std::string proto_hash;  // Hash of the structured query proto bytes.
    std::vector<std::string> columns;
    int64_t row_count = 0;
    double duration_ms = 0.0;
    std::optional<std::string> error;

    // For lazy materialization:
    std::vector<uint8_t> proto_data;  // Stored proto for deferred execution.
    // All query IDs this query depends on, extracted recursively from all
    // embedded query fields (inner_query, inner_query_id, join.left_query,
    // filter_to_intervals.base, etc.). Used for transitive invalidation:
    // if any dependency changes, this query must also be re-materialized.
    std::vector<std::string> inner_query_ids;
    bool needs_materialization = true;  // True until successfully materialized.
    bool is_view = false;  // Whether materialized as VIEW (not TABLE).
    std::string
        old_table_name;        // Old table/view to drop after new one created.
    bool old_is_view = false;  // Whether old_table_name is a VIEW.

    // Analysis results (populated during materialization):
    std::string sql;  // Complete runnable SQL (includes + preambles + query).
    std::string textproto;       // Text proto representation.
    std::string standalone_sql;  // Fully standalone SQL (no materialized refs).
  };

  // Computes a hash of raw proto bytes for change detection.
  std::string ComputeProtoHash(const uint8_t* data, size_t size);

  // Materializes a single query using a pre-configured generator.
  // The generator must have all queries added and modules/preambles executed.
  base::Status MaterializeQuery(
      const std::string& query_id,
      QueryState& state,
      perfetto_sql::generator::StructuredQueryGenerator& generator);

  // Collects all dependencies for a query (in materialization order).
  std::vector<std::string> CollectDependencies(const std::string& query_id);

  // Prepares the generator for materialization (adds queries, executes modules
  // and preambles). Called once per Query() invocation.
  base::Status PrepareGenerator(
      perfetto_sql::generator::StructuredQueryGenerator& generator,
      std::vector<std::vector<uint8_t>>& table_source_protos);

  // Drops a table or view by name.
  void DropTableOrView(const std::string& name, bool is_view);

  // Drops all materialized tables and views.
  void DropAll();

  // Generates standalone SQL for a query (deferred from materialization).
  void GenerateStandaloneSql(QueryState& state);

  TraceProcessor* tp_;
  DescriptorPool* descriptor_pool_;
  std::string id_;
  base::FlatHashMap<std::string, QueryState> query_states_;
  base::FlatHashMap<std::string, bool>
      included_modules_;  // Track included modules.
  uint32_t next_materialized_id_ = 0;
};

}  // namespace summary
}  // namespace perfetto::trace_processor

#endif  // SRC_TRACE_PROCESSOR_TRACE_SUMMARY_SUMMARIZER_H_
