// Copyright (C) 2025 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 {AsyncLimiter} from '../../base/async_limiter';
import {
  type AreaSelection,
  type AreaSelectionTab,
  areaSelectionsEqual,
} from '../../public/selection';
import type {Trace} from '../../public/trace';
import {Button} from '../../widgets/button';
import {EmptyState} from '../../widgets/empty_state';
import {Spinner} from '../../widgets/spinner';
import {type BenchmarkResult, runBenchmarks} from './benchmark';

function formatApproach(approach: string): string {
  switch (approach) {
    case 'uri_string':
      return 'URI String';
    case 'track_index':
      return 'Track Index';
    case 'groupid':
      return 'GroupID';
    case 'no_lineage':
      return 'No Lineage';
    default:
      return approach;
  }
}

function formatMs(ms: number): string {
  return ms.toFixed(2);
}

interface BenchmarkTableAttrs {
  results: BenchmarkResult[];
}

class BenchmarkTable implements m.ClassComponent<BenchmarkTableAttrs> {
  view({attrs}: m.CVnode<BenchmarkTableAttrs>) {
    const {results} = attrs;

    return m(
      'table.pf-benchmark-table',
      {
        style: {
          width: '100%',
          borderCollapse: 'collapse',
          fontFamily: 'monospace',
          fontSize: '12px',
        },
      },
      [
        m(
          'thead',
          m('tr', [
            m('th', {style: {textAlign: 'left', padding: '8px'}}, 'Approach'),
            m('th', {style: {textAlign: 'right', padding: '8px'}}, 'Tracks'),
            m('th', {style: {textAlign: 'right', padding: '8px'}}, 'Rows'),
            m(
              'th',
              {style: {textAlign: 'right', padding: '8px'}},
              'Build (ms)',
            ),
            m(
              'th',
              {style: {textAlign: 'right', padding: '8px'}},
              'Execute (ms)',
            ),
            m(
              'th',
              {style: {textAlign: 'right', padding: '8px'}},
              'Total (ms)',
            ),
          ]),
        ),
        m(
          'tbody',
          results.map((r) =>
            m('tr', {style: {borderTop: '1px solid var(--sys-border)'}}, [
              m('td', {style: {padding: '8px'}}, formatApproach(r.approach)),
              m(
                'td',
                {style: {textAlign: 'right', padding: '8px'}},
                r.trackCount,
              ),
              m(
                'td',
                {style: {textAlign: 'right', padding: '8px'}},
                r.rowCount.toLocaleString(),
              ),
              m(
                'td',
                {style: {textAlign: 'right', padding: '8px'}},
                formatMs(r.queryBuildTimeMs),
              ),
              m(
                'td',
                {style: {textAlign: 'right', padding: '8px'}},
                formatMs(r.queryExecuteTimeMs),
              ),
              m(
                'td',
                {
                  style: {
                    textAlign: 'right',
                    padding: '8px',
                    fontWeight: 'bold',
                  },
                },
                formatMs(r.totalTimeMs),
              ),
            ]),
          ),
        ),
      ],
    );
  }
}

export function createBenchmarkTab(trace: Trace): AreaSelectionTab {
  const limiter = new AsyncLimiter();
  let currentSelection: AreaSelection | undefined;
  let results: BenchmarkResult[] | undefined;
  let isLoading = false;

  return {
    id: 'aggregation_benchmark',
    name: 'Benchmark',
    render(selection: AreaSelection) {
      const selectionChanged =
        currentSelection === undefined ||
        !areaSelectionsEqual(selection, currentSelection);

      if (selectionChanged) {
        currentSelection = selection;
        results = undefined;
      }

      const runBenchmark = () => {
        limiter.schedule(async () => {
          isLoading = true;
          results = undefined;
          results = await runBenchmarks(trace.engine, selection.tracks);
          isLoading = false;
        });
      };

      if (isLoading) {
        return {
          isLoading: true,
          content: m(
            EmptyState,
            {
              icon: 'speed',
              title: 'Running benchmark...',
            },
            m(Spinner, {easing: true}),
          ),
        };
      }

      if (!results) {
        return {
          isLoading: false,
          content: m('div', {style: {padding: '16px', textAlign: 'center'}}, [
            m('p', `Selected ${selection.tracks.length} tracks`),
            m(Button, {
              label: 'Run Benchmark',
              onclick: runBenchmark,
            }),
          ]),
        };
      }

      return {
        isLoading: false,
        content: m('div', {style: {padding: '16px'}}, [
          m('h3', {style: {margin: '0 0 16px 0'}}, 'Benchmark Results'),
          m(BenchmarkTable, {results}),
          m(
            'div',
            {style: {marginTop: '16px'}},
            m(Button, {
              label: 'Re-run Benchmark',
              onclick: runBenchmark,
            }),
          ),
        ]),
      };
    },
  };
}
