// Copyright (C) 2023 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 m from 'mithril';

import {raf} from '../../core/raf_scheduler';
import {EngineProxy} from '../../trace_processor/engine';
import {STR} from '../../trace_processor/query_result';
import {FilterableSelect} from '../../widgets/select';
import {Spinner} from '../../widgets/spinner';
import {
  constraintsToQueryPrefix,
  constraintsToQuerySuffix,
  SQLConstraints,
} from '../sql_utils';

import {argColumn} from './column';
import {ArgSetIdColumn} from './table_description';

const MAX_ARGS_TO_DISPLAY = 15;

interface ArgumentSelectorAttrs {
  engine: EngineProxy;
  argSetId: ArgSetIdColumn;
  tableName: string;
  constraints: SQLConstraints;
  // List of aliases for existing columns by the table.
  alreadySelectedColumns: Set<string>;
  onArgumentSelected: (argument: string) => void;
}

// A widget which allows the user to select a new argument to display.
// Dinamically queries Trace Processor to find the relevant set of arg_set_ids
// and which args are present in these arg sets.
export class ArgumentSelector implements
    m.ClassComponent<ArgumentSelectorAttrs> {
  argList?: string[];

  constructor({attrs}: m.Vnode<ArgumentSelectorAttrs>) {
    this.load(attrs);
  }

  private async load(attrs: ArgumentSelectorAttrs) {
    const queryResult = await attrs.engine.query(`
      -- Encapsulate the query in a CTE to avoid clashes between filters
      -- and columns of the 'args' table.
      WITH arg_sets AS (
        ${constraintsToQueryPrefix(attrs.constraints)}
        SELECT DISTINCT ${attrs.tableName}.${attrs.argSetId.name} as arg_set_id
        FROM ${attrs.tableName}
        ${constraintsToQuerySuffix(attrs.constraints)}
      )
      SELECT
        DISTINCT args.key as key
      FROM arg_sets
      JOIN args USING (arg_set_id)
    `);
    this.argList = [];
    const it = queryResult.iter({key: STR});
    for (; it.valid(); it.next()) {
      const arg = argColumn(attrs.tableName, attrs.argSetId, it.key);
      if (attrs.alreadySelectedColumns.has(arg.alias)) continue;
      this.argList.push(it.key);
    }
    raf.scheduleFullRedraw();
  }

  view({attrs}: m.Vnode<ArgumentSelectorAttrs>) {
    if (this.argList === undefined) return m(Spinner);
    return m(FilterableSelect, {
      values: this.argList,
      onSelected: (value: string) => attrs.onArgumentSelected(value),
      maxDisplayedItems: MAX_ARGS_TO_DISPLAY,
      autofocusInput: true,
    });
  }
}
