// Copyright (C) 2026 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 {Icons} from '../../base/semantic_icons';
import type {
  AggregatePivotModel,
  Aggregation,
  Aggregator,
} from '../../components/aggregation_adapter';
import type {AreaSelection} from '../../public/selection';
import type {Trace} from '../../public/trace';
import {ANDROID_LOGS_TRACK_KIND} from '../../public/track_kinds';
import type {Engine} from '../../trace_processor/engine';
import {Anchor} from '../../widgets/anchor';

export class AndroidLogSelectionAggregator implements Aggregator {
  readonly id = 'android_log_aggregation';

  constructor(private readonly trace: Trace) {}

  probe(area: AreaSelection): Aggregation | undefined {
    const logTracks = area.tracks.filter((t) =>
      t.tags?.kinds?.includes(ANDROID_LOGS_TRACK_KIND),
    );

    if (logTracks.length === 0) return undefined;

    const utids = logTracks
      .map((t) => t.tags?.utid as number | undefined)
      .filter((u): u is number => u !== undefined);

    return {
      prepareData: async (engine: Engine) => {
        let whereClause = `al.ts >= ${area.start} AND al.ts <= ${area.end}`;
        if (utids.length > 0) {
          whereClause += ` AND al.utid IN (${utids.join(', ')})`;
        }

        await engine.query(`
          CREATE OR REPLACE PERFETTO TABLE ${this.id} AS
          SELECT
            al.id,
            al.ts,
            al.prio,
            al.tag,
            al.msg,
            t.tid,
            t.name AS thread_name,
            p.pid,
            p.name AS process_name
          FROM android_logs al
          LEFT JOIN thread t ON al.utid = t.utid
          LEFT JOIN process p ON t.upid = p.upid
          WHERE ${whereClause}
        `);

        return {tableName: this.id};
      },
    };
  }

  getTabName() {
    return 'Android Logs';
  }

  getColumnDefinitions(): AggregatePivotModel {
    return {
      groupBy: [
        {id: 'tag', field: 'tag'},
        {id: 'prio', field: 'prio'},
      ],
      aggregates: [{id: 'count', function: 'COUNT'}],
      columns: [
        {
          title: 'ID',
          columnId: 'id',
          formatHint: 'NUMERIC',
          cellRenderer: (value) => {
            const id = typeof value === 'bigint' ? Number(value) : value;
            if (typeof id !== 'number') return String(value);
            return m(
              Anchor,
              {
                icon: Icons.UpdateSelection,
                onclick: () => {
                  this.trace.selection.selectSqlEvent('android_logs', id, {
                    scrollToSelection: true,
                  });
                },
              },
              String(id),
            );
          },
        },
        {title: 'Timestamp', columnId: 'ts', formatHint: 'TIMESTAMP_NS'},
        {title: 'Priority', columnId: 'prio', formatHint: 'NUMERIC'},
        {title: 'Tag', columnId: 'tag', formatHint: 'STRING'},
        {title: 'Message', columnId: 'msg', formatHint: 'STRING'},
        {title: 'TID', columnId: 'tid', formatHint: 'NUMERIC'},
        {title: 'Thread', columnId: 'thread_name', formatHint: 'STRING'},
        {title: 'PID', columnId: 'pid', formatHint: 'NUMERIC'},
        {title: 'Process', columnId: 'process_name', formatHint: 'STRING'},
      ],
    };
  }
}
