// 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 type {TrackEventDetailsPanel} from '../../public/details_panel';
import type {SqlValue} from '../../trace_processor/query_result';
import {sqlValueToReadableString} from '../../trace_processor/sql_utils';
import {DetailsShell} from '../../widgets/details_shell';
import {GridLayout} from '../../widgets/grid_layout';
import {Section} from '../../widgets/section';
import {SqlRef} from '../../widgets/sql_ref';
import {Tree, TreeNode} from '../../widgets/tree';
import type {Trace} from '../../public/trace';

export interface ColumnConfig {
  readonly displayName?: string;
}

export type Columns = {
  readonly [columnName: string]: ColumnConfig;
};

// A details tab, which fetches slice-like object from a given SQL table by id
// and renders it according to the provided config, specifying which columns
// need to be rendered and how.
export class GenericSliceDetailsTab implements TrackEventDetailsPanel {
  private data?: {[key: string]: SqlValue};

  constructor(
    private readonly trace: Trace,
    private readonly sqlTableName: string,
    private readonly id: number,
    private readonly title: string,
    private readonly columns?: Columns,
  ) {}

  async load() {
    const result = await this.trace.engine.query(
      `select * from ${this.sqlTableName} where id = ${this.id}`,
    );

    this.data = result.firstRow({});
  }

  render() {
    if (!this.data) {
      return m('h2', 'Loading');
    }

    const columns = this.columns;
    const data = this.data;

    const detailNodes =
      columns !== undefined
        ? Object.keys(columns).map((key) => {
            const argKey = columns[key].displayName ?? key;
            return m(TreeNode, {
              left: argKey,
              right: sqlValueToReadableString(data[key]),
            });
          })
        : Object.keys(this.data).map((key) => {
            return m(TreeNode, {
              left: key,
              right: sqlValueToReadableString(data[key]),
            });
          });

    return m(
      DetailsShell,
      {
        title: this.title,
      },
      m(
        GridLayout,
        m(Section, {title: 'Details'}, m(Tree, detailNodes)),
        m(
          Section,
          {title: 'Metadata'},
          m(Tree, [
            m(TreeNode, {
              left: 'SQL ID',
              right: m(SqlRef, {
                table: this.sqlTableName,
                id: this.id,
              }),
            }),
          ]),
        ),
      ),
    );
  }
}
