// Copyright 2022 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/kit/kit.js';
import '../../../ui/legacy/components/data_grid/data_grid.js';

import * as i18n from '../../../core/i18n/i18n.js';
import type * as Protocol from '../../../generated/protocol.js';
import * as UI from '../../../ui/legacy/legacy.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';

import sharedStorageAccessGridStyles from './sharedStorageAccessGrid.css.js';

const SHARED_STORAGE_EXPLANATION_URL =
    'https://developers.google.com/privacy-sandbox/private-advertising/shared-storage';

const {render, html} = Lit;

const UIStrings = {
  /**
   * @description Text in Shared Storage Events View of the Application panel
   */
  sharedStorage: 'Shared storage',
  /**
   * @description Hover text for an info icon in the Shared Storage Events panel
   */
  allSharedStorageEvents: 'All shared storage events for this page.',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Date and time of an Shared Storage event in a locale-
   * dependent format.
   */
  eventTime: 'Event Time',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Scope of shared storage event such as 'window', 'sharedStorageWorklet',
   * 'protectedAudienceWorklet', or 'header'.
   */
  eventScope: 'Access Scope',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Method of shared storage event such as 'addModule', 'run', 'set', 'delete',
   * or 'get'.
   */
  eventMethod: 'Access Method',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Owner origin of the shared storage for this access event.
   */
  ownerOrigin: 'Owner Origin',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Owner site of the shared storage for this access event.
   */
  ownerSite: 'Owner Site',
  /**
   * @description Text in Shared Storage Events View of the Application panel
   * Event parameters whose presence/absence depend on the access type.
   */
  eventParams: 'Optional Event Params',
  /**
   * @description Text shown when no shared storage event is shown.
   * Shared storage allows to store and access data that can be shared across different sites.
   * A shared storage event is for example an access from a site to that storage.
   */
  noEvents: 'No shared storage events detected',
  /**
   * @description Text shown when no shared storage event is shown. It explains the shared storage event page.
   * Shared storage allows to store and access data that can be shared across different sites.
   * A shared storage event is for example an access from a site to that storage.
   */
  sharedStorageDescription:
      'On this page you can view, add, edit and delete shared storage key-value pairs and view shared storage events.',
  /**
   * @description Text used in a link to learn more about the topic.
   */
  learnMore: 'Learn more',

} as const;

const str_ = i18n.i18n.registerUIStrings('panels/application/components/SharedStorageAccessGrid.ts', UIStrings);
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

export interface ViewInput {
  events: Protocol.Storage.SharedStorageAccessedEvent[];
  onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => void;
}
export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
export const DEFAULT_VIEW: View = (input, _output, target) => {
  // clang-format off
  render(html`
    <style>${sharedStorageAccessGridStyles}</style>
    ${input.events.length === 0
      ? html`
        <div class="empty-state" jslog=${VisualLogging.section().context('empty-view')}>
          <div class="empty-state-header">${i18nString(UIStrings.noEvents)}</div>
          <div class="empty-state-description">
            <span>${i18nString(UIStrings.sharedStorageDescription)}</span>
            <devtools-link
              class="devtools-link"
              href=${SHARED_STORAGE_EXPLANATION_URL}
              .jslogContext=${'learn-more'}
            >${i18nString(UIStrings.learnMore)}</devtools-link>
          </div>
        </div>`
      : html`
        <div jslog=${VisualLogging.section('events-table')}>
          <span class="heading">${i18nString(UIStrings.sharedStorage)}</span>
          <devtools-icon class="info-icon medium" name="info"
                          title=${i18nString(UIStrings.allSharedStorageEvents)}>
          </devtools-icon>
          <devtools-data-grid striped inline>
            <table>
              <thead>
                <tr>
                  <th id="event-time" weight="10" sortable>
                    ${i18nString(UIStrings.eventTime)}
                  </th>
                  <th id="event-scope" weight="10" sortable>
                    ${i18nString(UIStrings.eventScope)}
                  </th>
                  <th id="event-method" weight="10" sortable>
                    ${i18nString(UIStrings.eventMethod)}
                  </th>
                  <th id="event-owner-origin" weight="10" sortable>
                    ${i18nString(UIStrings.ownerOrigin)}
                  </th>
                  <th id="event-owner-site" weight="10" sortable>
                    ${i18nString(UIStrings.ownerSite)}
                  </th>
                  <th id="event-params" weight="10" sortable>
                    ${i18nString(UIStrings.eventParams)}
                  </th>
                </tr>
              </thead>
              <tbody>
                ${input.events.map(event => html`
                  <tr @select=${() =>input.onSelect(event)}>
                    <td data-value=${event.accessTime}>
                      ${new Date(1e3 * event.accessTime).toLocaleString()}
                    </td>
                    <td>${event.scope}</td>
                    <td>${event.method}</td>
                    <td>${event.ownerOrigin}</td>
                    <td>${event.ownerSite}</td>
                    <td>${JSON.stringify(event.params)}</td>
                  </tr>
                `)}
              </tbody>
            </table>
          </devtools-data-grid>
        </div>`}`, target);
  // clang-format on
};

export class SharedStorageAccessGrid extends UI.Widget.Widget {
  readonly #view: View;
  #events: Protocol.Storage.SharedStorageAccessedEvent[] = [];
  #onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => void = () => {};

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

  set events(events: Protocol.Storage.SharedStorageAccessedEvent[]) {
    this.#events = events;
    this.performUpdate();
  }

  set onSelect(onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => unknown) {
    this.#onSelect = onSelect;
    this.performUpdate();
  }

  get onSelect(): (event: Protocol.Storage.SharedStorageAccessedEvent) => unknown {
    return this.#onSelect;
  }

  override performUpdate(): void {
    this.#view(
        {
          events: this.#events,
          onSelect: this.#onSelect.bind(this),
        },
        {}, this.contentElement);
  }
}
