// Copyright (C) 2020 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 {SimpleResizeObserver} from '../../base/resize_observer';
import {undoCommonChatAppReplacements} from '../../base/string_utils';
import {QueryResponse, runQuery} from '../../components/query_table/queries';
import {Callout} from '../../widgets/callout';
import {Editor} from '../../widgets/editor';
import {PageWithTraceAttrs} from '../../public/page';
import {QueryHistoryComponent, queryHistoryStorage} from './query_history';
import {Trace, TraceAttrs} from '../../public/trace';
import {addQueryResultsTab} from '../../components/query_table/query_result_tab';
import {QueryTable} from '../../components/query_table/query_table';

interface QueryPageState {
  enteredText: string;
  executedQuery?: string;
  queryResult?: QueryResponse;
  heightPx: string;
  generation: number;
}

const state: QueryPageState = {
  enteredText: '',
  heightPx: '100px',
  generation: 0,
};

function runManualQuery(trace: Trace, query: string) {
  state.executedQuery = query;
  state.queryResult = undefined;
  runQuery(undoCommonChatAppReplacements(query), trace.engine).then(
    (resp: QueryResponse) => {
      addQueryResultsTab(
        trace,
        {
          query: query,
          title: 'Standalone Query',
          prefetchedResponse: resp,
        },
        'analyze_page_query',
      );
      // We might have started to execute another query. Ignore it in that
      // case.
      if (state.executedQuery !== query) {
        return;
      }
      state.queryResult = resp;
      trace.scheduleFullRedraw();
    },
  );
}

export type QueryInputAttrs = TraceAttrs;

class QueryInput implements m.ClassComponent<QueryInputAttrs> {
  private resize?: Disposable;

  oncreate({dom}: m.CVnodeDOM<QueryInputAttrs>): void {
    this.resize = new SimpleResizeObserver(dom, () => {
      state.heightPx = (dom as HTMLElement).style.height;
    });
    (dom as HTMLElement).style.height = state.heightPx;
  }

  onremove(): void {
    if (this.resize) {
      this.resize[Symbol.dispose]();
      this.resize = undefined;
    }
  }

  view({attrs}: m.CVnode<QueryInputAttrs>) {
    return m(Editor, {
      generation: state.generation,
      initialText: state.enteredText,

      onExecute: (text: string) => {
        if (!text) {
          return;
        }
        queryHistoryStorage.saveQuery(text);
        runManualQuery(attrs.trace, text);
      },

      onUpdate: (text: string) => {
        state.enteredText = text;
        attrs.trace.scheduleFullRedraw();
      },
    });
  }
}

export class QueryPage implements m.ClassComponent<PageWithTraceAttrs> {
  view({attrs}: m.CVnode<PageWithTraceAttrs>) {
    return m(
      '.query-page',
      m(Callout, 'Enter query and press Cmd/Ctrl + Enter'),
      state.enteredText.includes('"') &&
        m(
          Callout,
          {icon: 'warning'},
          `" (double quote) character observed in query; if this is being used to ` +
            `define a string, please use ' (single quote) instead. Using double quotes ` +
            `can cause subtle problems which are very hard to debug.`,
        ),
      m(QueryInput, attrs),
      state.executedQuery === undefined
        ? null
        : m(QueryTable, {
            trace: attrs.trace,
            query: state.executedQuery,
            resp: state.queryResult,
            fillParent: false,
          }),
      m(QueryHistoryComponent, {
        trace: attrs.trace,
        runQuery: (q: string) => runManualQuery(attrs.trace, q),
        setQuery: (q: string) => {
          state.enteredText = q;
          state.generation++;
          attrs.trace.scheduleFullRedraw();
        },
      }),
    );
  }
}
