// Copyright (C) 2024 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.

import type {TableColumn} from '../../components/widgets/sql/table/table_column';
import type {SqlTableDefinition} from '../../components/widgets/sql/table/table_description';
import type {PerfettoSqlType} from '../../trace_processor/perfetto_sql_type';

// Handles the access to all of the Perfetto SQL modules accessible to Trace
//  Processor.
export interface SqlModules {
  // Returns all tables/views between all loaded Perfetto SQL modules.
  listTables(): SqlTable[];

  // Returns all loaded Perfetto SQL modules.
  listModules(): SqlModule[];

  // Returns names of all tables/views between all loaded Perfetto SQL modules.
  listTablesNames(): string[];

  // Returns Perfetto SQL table/view if it was loaded in one of the Perfetto
  // SQL module.
  getTable(tableName: string): SqlTable | undefined;

  // Returns module that contains Perfetto SQL table/view if it was loaded in one of the Perfetto
  // SQL module.
  getModuleForTable(tableName: string): SqlModule | undefined;

  // Returns true if the module is disabled due to missing data in the trace.
  isModuleDisabled(moduleName: string): boolean;

  // Returns whether a specific table passed its own data availability check.
  // Returns undefined if no per-table check exists for this table.
  // When undefined, callers fall back to isModuleDisabled.
  tablePassedDataCheck?(tableName: string): boolean | undefined;

  // Returns the set of all disabled module names.
  getDisabledModules(): ReadonlySet<string>;

  // Triggers the data availability checks if not already started.
  // Safe to call multiple times - subsequent calls are no-ops.
  // Returns a promise that resolves when initialization is complete.
  ensureInitialized(): Promise<void>;
}

// Handles the access to a specific Perfetto SQL Package. Package consists of
// Perfetto SQL modules.
export interface SqlPackage {
  readonly name: string;
  readonly modules: SqlModule[];

  // Returns all tables/views in this package.
  listTables(): SqlTable[];

  // Returns names of all tables/views in this package.
  listTablesNames(): string[];

  getTable(tableName: string): SqlTable | undefined;

  // Returns sqlModule containing table with provided name.
  getModuleForTable(tableName: string): SqlModule | undefined;

  // Returns sqlTableDefinition of the table with provided name.
  getSqlTableDefinition(tableName: string): SqlTableDefinition | undefined;
}

// Handles the access to a specific Perfetto SQL module.
export interface SqlModule {
  readonly includeKey: string;
  readonly tags: string[];
  readonly tables: SqlTable[];
  readonly functions: SqlFunction[];
  readonly tableFunctions: SqlTableFunction[];
  readonly macros: SqlMacro[];

  // Returns sqlTable with provided name.
  getTable(tableName: string): SqlTable | undefined;

  // Returns sqlTableDefinition of the table with provided name.
  getSqlTableDefinition(tableName: string): SqlTableDefinition | undefined;
}

// The definition of Perfetto SQL table/view.
export interface SqlTable {
  readonly name: string;
  readonly includeKey?: string;
  readonly description: string;
  readonly type: string;
  readonly importance?: 'core' | 'high' | 'mid' | 'low';
  readonly dataCheckSql?: string;
  readonly columns: SqlColumn[];

  // Returns all columns as TableColumns.
  getTableColumns(): TableColumn[];
}

// The definition of Perfetto SQL function.
export interface SqlFunction {
  readonly name: string;
  readonly description: string;
  readonly args: SqlArgument[];
  readonly returnType: string;
  readonly returnDesc: string;
}

// The definition of Perfetto SQL table function.
export interface SqlTableFunction {
  readonly name: string;
  readonly description: string;
  readonly args: SqlArgument[];
  readonly returnCols: SqlColumn[];
}

// The definition of Perfetto SQL macro.
export interface SqlMacro {
  readonly name: string;
  readonly description: string;
  readonly args: SqlArgument[];
  readonly returnType: string;
}

// The definition of Perfetto SQL column.
export interface SqlColumn {
  readonly name: string;
  readonly description?: string;
  readonly type?: PerfettoSqlType;
}

// The definition of Perfetto SQL argument. Can be used for functions, table
// functions or macros.
export interface SqlArgument {
  readonly name: string;
  readonly description: string;
  readonly type: string;
}

export interface TableAndColumn {
  table: string;
  column: string;

  isEqual(o: TableAndColumn): boolean;
}

// Returns true if a table should be considered disabled (no data).
// Uses table-level availability when known, falls back to module-level.
export function isTableEffectivelyDisabled(
  sqlModules: SqlModules,
  tableName: string,
): boolean {
  const availability = sqlModules.tablePassedDataCheck?.(tableName);
  if (availability !== undefined) {
    return !availability;
  }
  const module = sqlModules.getModuleForTable(tableName);
  return module !== undefined && sqlModules.isModuleDisabled(module.includeKey);
}
