// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../../../ui/legacy/components/data_grid/data_grid.js';

import * as Host from '../../../core/host/host.js';
import * as i18n from '../../../core/i18n/i18n.js';
import type * as TextUtils from '../../../models/text_utils/text_utils.js';
import * as UI from '../../../ui/legacy/legacy.js';
import {html, render} from '../../../ui/lit/lit.js';

const UIStrings = {
  /**
   * @description Text in Crash Report Context Items View of the Application panel
   */
  key: 'Key',
  /**
   * @description Text in Crash Report Context Items View of the Application panel
   */
  value: 'Value',
  /**
   * @description Context menu item to copy the key of a context entry
   */
  copyKey: 'Copy key',
  /**
   * @description Context menu item to copy the value of a context entry
   */
  copyValue: 'Copy value',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/application/components/CrashReportContextGrid.ts', UIStrings);
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

export interface CrashReportContextGridData {
  entries: Array<{key: string, value: string}>;
  selectedKey?: string;
  filters?: TextUtils.TextUtils.ParsedFilter[];
}

export interface ViewInput {
  entries: Array<{key: string, value: string}>;
  selectedKey?: string;
  onSelect: (key: string) => void;
  onContextMenu: (e: Event, key: string, value: string) => void;
}

export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLElement|ShadowRoot): void => {
  // clang-format off
  render(
      html`
      <style>
        :host {
          display: block;
        }

        div {
          overflow: auto;
        }

        td {
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
      </style>
      <style>${UI.inspectorCommonStyles}</style>
      <div>
        <devtools-data-grid striped inline>
          <table>
            <thead>
              <tr>
                <th id="key" weight="50">${i18nString(UIStrings.key)}</th>
                <th id="value" weight="50">${i18nString(UIStrings.value)}</th>
              </tr>
            </thead>
            <tbody>
              ${input.entries.map(entry => html`
                <tr class=${input.selectedKey === entry.key ? 'selected' : ''}
                    @select=${() => input.onSelect(entry.key)}
                    @contextmenu=${(e: Event) => input.onContextMenu(e, entry.key, entry.value)}>
                  <td title=${entry.key}>${entry.key}</td>
                  <td title=${entry.value}>${entry.value}</td>
                </tr>
              `)}
            </tbody>
          </table>
        </devtools-data-grid>
      </div>
    `,
      target);
  // clang-format on
};

type View = (input: ViewInput, output: undefined, target: HTMLElement|ShadowRoot) => void;

export class CrashReportContextGrid extends UI.Widget.Widget {
  #entries: Array<{key: string, value: string}> = [];
  #filteredEntries: Array<{key: string, value: string}> = [];
  #selectedKey?: string;
  #filters: TextUtils.TextUtils.ParsedFilter[] = [];
  readonly #view: View;

  constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
    super(element, {useShadowDom: true});
    this.#view = view;
  }

  set data(data: CrashReportContextGridData) {
    this.#entries = data.entries;
    this.#selectedKey = data.selectedKey;
    this.#filters = data.filters || [];
    this.requestUpdate();
  }

  #computeFilteredEntries(): void {
    if (this.#filters.length === 0) {
      this.#filteredEntries = this.#entries;
      return;
    }
    this.#filteredEntries = this.#entries.filter(entry => {
      return this.#filters.every(filter => {
        const regex = filter.regex;
        if (!regex) {
          return true;
        }
        const matches = regex.test(entry.key) || regex.test(entry.value);
        return filter.negative ? !matches : matches;
      });
    });
  }

  #onContextMenu(e: Event, key: string, value: string): void {
    const customEvent = e as CustomEvent<UI.ContextMenu.ContextMenu>;
    const contextMenu = customEvent.detail;
    contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyKey), () => {
      Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(key);
    }, {jslogContext: 'copy-key'});
    contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyValue), () => {
      Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(value);
    }, {jslogContext: 'copy-value'});
  }

  override performUpdate(): void {
    this.#computeFilteredEntries();
    this.#view(
        {
          entries: this.#filteredEntries,
          selectedKey: this.#selectedKey,
          onSelect: (key: string) => this.element.dispatchEvent(new CustomEvent('select', {detail: key})),
          onContextMenu: (e: Event, key: string, value: string) => this.#onContextMenu(e, key, value),
        },
        undefined, this.contentElement);
  }
}
