// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable @devtools/no-imperative-dom-api */

import * as i18n from '../../core/i18n/i18n.js';
import * as Protocol from '../../generated/protocol.js';
import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';

import * as ApplicationComponents from './components/components.js';
import interestGroupStorageViewStyles from './interestGroupStorageView.css.js';

const UIStrings = {
  /**
   * @description Placeholder text shown when nothing has been selected for display
   *details.
   * An interest group is an ad targeting group stored on the browser that can
   * be used to show a certain set of advertisements in the future as the
   * outcome of a FLEDGE auction.
   */
  noValueSelected: 'No interest group selected',
  /**
   * @description Placeholder text instructing the user how to display interest group
   *details.
   * An interest group is an ad targeting group stored on the browser that can
   * be used to show a certain set of advertisements in the future as the
   * outcome of a FLEDGE auction.
   */
  clickToDisplayBody: 'Select any interest group event to display the group\'s current state',
  /**
   * @description Placeholder text telling the user no details are available for
   *the selected interest group.
   */
  noDataAvailable: 'No details available',
  /**
   * @description Placeholder text explaining to the user a potential reason for not having details on
   * the interest groups.
   * An interest group is an ad targeting group stored on the browser that can
   * be used to show a certain set of advertisements in the future as the
   * outcome of a FLEDGE auction.
   */
  noDataDescription: 'The browser may have left the group.',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/application/InterestGroupStorageView.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

interface InterestGroupDetailsGetter {
  getInterestGroupDetails: (owner: string, name: string) => Promise<object|null>;
}

function eventEquals(
    a: Protocol.Storage.InterestGroupAccessedEvent, b: Protocol.Storage.InterestGroupAccessedEvent): boolean {
  return (a.accessTime === b.accessTime && a.type === b.type && a.ownerOrigin === b.ownerOrigin && a.name === b.name);
}

export class InterestGroupStorageView extends UI.SplitWidget.SplitWidget {
  private readonly interestGroupGrid = new ApplicationComponents.InterestGroupAccessGrid.InterestGroupAccessGrid();
  private events: Protocol.Storage.InterestGroupAccessedEvent[] = [];
  private detailsGetter: InterestGroupDetailsGetter;
  private noDataView: UI.Widget.VBox;
  private noDisplayView: UI.Widget.VBox;

  constructor(detailsGetter: InterestGroupDetailsGetter) {
    super(/* isVertical */ false, /* secondIsSidebar: */ true);
    this.element.setAttribute('jslog', `${VisualLogging.pane('interest-groups')}`);
    this.detailsGetter = detailsGetter;

    const topPanel = new UI.Widget.VBox();
    this.noDisplayView =
        new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noValueSelected), i18nString(UIStrings.clickToDisplayBody));
    this.noDataView =
        new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noDataAvailable), i18nString(UIStrings.noDataDescription));

    topPanel.setMinimumSize(0, 120);
    this.setMainWidget(topPanel);
    this.noDisplayView.setMinimumSize(0, 80);
    this.setSidebarWidget(this.noDisplayView);
    this.noDataView.setMinimumSize(0, 80);
    this.noDisplayView.contentElement.setAttribute('jslog', `${VisualLogging.pane('details').track({resize: true})}`);
    this.noDataView.contentElement.setAttribute('jslog', `${VisualLogging.pane('details').track({resize: true})}`);
    this.hideSidebar();

    topPanel.contentElement.appendChild(this.interestGroupGrid);
    this.interestGroupGrid.addEventListener('select', this.onFocus.bind(this));
  }

  override wasShown(): void {
    super.wasShown();
    const mainWidget = this.mainWidget();
    if (mainWidget) {
      mainWidget.registerRequiredCSS(interestGroupStorageViewStyles);
    }
  }

  addEvent(event: Protocol.Storage.InterestGroupAccessedEvent): void {
    if (this.showMode() !== UI.SplitWidget.ShowMode.BOTH) {
      this.showBoth();
    }
    // Only add if not already present.
    const foundEvent = this.events.find(t => eventEquals(t, event));
    if (!foundEvent) {
      this.events.push(event);
      this.interestGroupGrid.data = this.events;
    }
  }

  clearEvents(): void {
    this.events = [];
    this.interestGroupGrid.data = this.events;
    this.setSidebarWidget(this.noDisplayView);
    this.sidebarUpdatedForTesting();
  }

  private async onFocus(event: Event): Promise<void> {
    const focusedEvent = event as CustomEvent<Protocol.Storage.InterestGroupAccessedEvent>;
    const {ownerOrigin, name, type: eventType} = focusedEvent.detail;

    let details = null;
    // Details of additional bids can't be looked up like regular bids,
    // they are ephemeral to the auction.
    if (eventType !== Protocol.Storage.InterestGroupAccessType.AdditionalBid &&
        eventType !== Protocol.Storage.InterestGroupAccessType.AdditionalBidWin &&
        eventType !== Protocol.Storage.InterestGroupAccessType.TopLevelAdditionalBid) {
      details = await this.detailsGetter.getInterestGroupDetails(ownerOrigin, name);
    }
    if (details) {
      const jsonView = await SourceFrame.JSONView.JSONView.createView(JSON.stringify(details));
      jsonView?.setMinimumSize(0, 40);
      if (jsonView) {
        jsonView.contentElement.setAttribute('jslog', `${VisualLogging.pane('details').track({resize: true})}`);
        this.setSidebarWidget(jsonView);
      }
    } else {
      this.setSidebarWidget(this.noDataView);
    }
    this.sidebarUpdatedForTesting();
  }

  getEventsForTesting(): Protocol.Storage.InterestGroupAccessedEvent[] {
    return this.events;
  }

  getInterestGroupGridForTesting(): ApplicationComponents.InterestGroupAccessGrid.InterestGroupAccessGrid {
    return this.interestGroupGrid;
  }

  sidebarUpdatedForTesting(): void {
  }
}
