// 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 i18n from '../../core/i18n/i18n.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as Protocol from '../../generated/protocol.js';
import * as UI from '../../ui/legacy/legacy.js';
import {html, nothing, render} from '../../ui/lit/lit.js';
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';

import requestDeviceBoundSessionsViewStyles from './requestDeviceBoundSessionsView.css.js';

const UIStrings = {
  /**
   * @description Heading for the ID of a session.
   */
  sessionId: 'Session ID',
  /**
   * @description Heading for the decision on whether an HTTP request was deferred. (i.e. paused and
   * later unpaused).
   */
  deferralDecision: 'Deferral decision',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was deferred (i.e. paused and later unpaused). The reasoning for the deferral
   * is that there was a refresh.
   */
  deferred: 'Deferred (Refresh)',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was not deferred (i.e. not paused and later unpaused). The reasoning for it
   * not being deferred is that there was a refresh attempted proactively.
   */
  proactiveRefreshAttempted: 'Not deferred (Proactive refresh attempted)',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was not deferred (i.e. not paused and later unpaused). The reasoning for it
   * not being deferred is that while the HTTP request is in scope of a session, it was
   * not possible to trigger a refresh proactively.
   */
  proactiveRefreshNotPossible: 'Not deferred (Request is in scope of session but proactive refresh is not possible)',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was not deferred (i.e. not paused and later unpaused). The reasoning for it
   * not being deferred is that while the HTTP request is in scope of a session, the HTTP
   * request's initiator is not allowed to trigger a refresh.
   */
  inScopeRefreshNotAllowed:
      'Not deferred (Request is in scope of session but initiator is not allowed to trigger refresh)',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was not deferred (i.e. not paused and later unpaused). The reasoning for it
   * not being deferred is that while the HTTP request is in scope of a session, the
   * session's cookies are still present, so there is no need to trigger a refresh yet.
   */
  inScopeRefreshNotYetNeeded: 'Not deferred (Request is in scope of session but cookies are still present)',
  /**
   * @description One of the HTTP request deferral decisions. This one notes that the
   * request was not deferred (i.e. not paused and later unpaused). The reasoning for it
   * not being deferred is that the HTTP request is not in scope of a session.
   */
  notInScope: 'Not deferred (Request is not in scope of session)',
} as const;

const str_ = i18n.i18n.registerUIStrings('panels/network/RequestDeviceBoundSessionsView.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

interface ViewInput {
  deviceBoundSessionUsages: Protocol.Network.DeviceBoundSessionWithUsage[];
}

type ViewOutput = object;

export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTMLElement): void => {
  const {deviceBoundSessionUsages} = input;

  render(
      html`
      <style>${UI.inspectorCommonStyles}</style>
      <style>${requestDeviceBoundSessionsViewStyles}</style>
      <div class="request-device-bound-sessions-view">
        ${
          deviceBoundSessionUsages.length > 0 ? html`
            <div class="device-bound-session-grid-wrapper">
              <devtools-data-grid striped inline>
                <table>
                  <thead>
                    <tr>
                      <th id="session-id" sortable>${i18nString(UIStrings.sessionId)}</th>
                      <th id="deferral-decision" sortable>${i18nString(UIStrings.deferralDecision)}</th>
                    </tr>
                  </thead>
                  <tbody>
                    ${deviceBoundSessionUsages.map(session => html`
                      <tr>
                        <td>${session.sessionKey.id}</td>
                        <td>${getDeferralDecision(session.usage)}</td>
                      </tr>
                    `)}
                  </tbody>
                </table>
              </devtools-data-grid>
            </div>
          ` :
                                                nothing}
      </div>
    `,
      target);
};

export class RequestDeviceBoundSessionsView extends UI.Widget.VBox {
  #request: SDK.NetworkRequest.NetworkRequest;
  #view: typeof DEFAULT_VIEW;

  constructor(request: SDK.NetworkRequest.NetworkRequest, view: typeof DEFAULT_VIEW = DEFAULT_VIEW) {
    super({jslog: `${VisualLogging.pane('device-bound-sessions-request')}`});
    this.#request = request;
    this.#view = view;
  }

  override wasShown(): void {
    super.wasShown();
    this.#request.addEventListener(SDK.NetworkRequest.Events.RESPONSE_HEADERS_CHANGED, this.performUpdate, this);
    this.performUpdate();
  }

  override willHide(): void {
    super.willHide();
    this.#request.removeEventListener(SDK.NetworkRequest.Events.RESPONSE_HEADERS_CHANGED, this.performUpdate, this);
  }

  override performUpdate(): void {
    if (!this.isShowing()) {
      return;
    }
    this.#view({deviceBoundSessionUsages: this.#request.getDeviceBoundSessionUsages()}, {}, this.contentElement);
  }
}

function getDeferralDecision(usage: Protocol.Network.DeviceBoundSessionWithUsageUsage): string {
  switch (usage) {
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.NotInScope:
      return i18nString(UIStrings.notInScope);
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.InScopeRefreshNotYetNeeded:
      return i18nString(UIStrings.inScopeRefreshNotYetNeeded);
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.InScopeRefreshNotAllowed:
      return i18nString(UIStrings.inScopeRefreshNotAllowed);
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.ProactiveRefreshNotPossible:
      return i18nString(UIStrings.proactiveRefreshNotPossible);
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.ProactiveRefreshAttempted:
      return i18nString(UIStrings.proactiveRefreshAttempted);
    case Protocol.Network.DeviceBoundSessionWithUsageUsage.Deferred:
      return i18nString(UIStrings.deferred);
    default:
      return usage;
  }
}
