// 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 * as i18n from '../../../core/i18n/i18n.js';
import * as Platform from '../../../core/platform/platform.js';
import type * as SDK from '../../../core/sdk/sdk.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 * as NetworkForward from '../forward/forward.js';

import {EditingAllowedStatus, type HeaderDescriptor} from './HeaderSectionRow.js';
import requestHeaderSectionStyles from './RequestHeaderSection.css.js';
import requestHeadersViewStyles from './RequestHeadersView.css.js';

export {requestHeadersViewStyles};

const {render, html} = Lit;

const UIStrings = {
  /**
   * @description Text that is usually a hyperlink to more documentation
   */
  learnMore: 'Learn more',
  /**
   * @description Message to explain lack of raw headers for a particular network request
   */
  provisionalHeadersAreShownDisableCache: 'Provisional headers are shown. Disable cache to see full headers.',
  /**
   * @description Tooltip to explain lack of raw headers for a particular network request
   */
  onlyProvisionalHeadersAre:
      'Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn’t store the original request headers. Disable cache to see full request headers.',
  /**
   * @description Message to explain lack of raw headers for a particular network request
   */
  provisionalHeadersAreShown: 'Provisional headers are shown.',
} as const;

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

export interface ViewInput {
  headers: HeaderDescriptor[];
  isProvisionalHeaders: boolean;
  isRequestCached: boolean;
}

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

export const DEFAULT_VIEW: View = (input, output, target) => {
  const headers = input.headers;

  // Disabled until https://crbug.com/1079231 is fixed.
  // clang-format off
  render(html`
    <style>${requestHeaderSectionStyles}</style>
    ${input.isProvisionalHeaders ? renderProvisionalHeadersWarning(input.isRequestCached) : Lit.nothing}
    ${headers.map(header => html`
      <devtools-header-section-row
        .data=${{ header }}
        jslog=${VisualLogging.item('request-header').track({resize: true})}
      ></devtools-header-section-row>
    `)}
  `, target);
  // clang-format on
};

function renderProvisionalHeadersWarning(isRequestCached: boolean): Lit.LitTemplate {
  let cautionText;
  let cautionTitle = '';
  if (isRequestCached) {
    cautionText = i18nString(UIStrings.provisionalHeadersAreShownDisableCache);
    cautionTitle = i18nString(UIStrings.onlyProvisionalHeadersAre);
  } else {
    cautionText = i18nString(UIStrings.provisionalHeadersAreShown);
  }
  // Disabled until https://crbug.com/1079231 is fixed.
  // clang-format off
  return html`
    <div class="call-to-action">
      <div class="call-to-action-body">
        <div class="explanation" title=${cautionTitle}>
          <devtools-icon class="inline-icon medium" name='warning-filled'>
          </devtools-icon>
          ${cautionText} <devtools-link href="https://developer.chrome.com/docs/devtools/network/reference/#provisional-headers" class="link">${i18nString(UIStrings.learnMore)}</devtools-link>
        </div>
      </div>
    </div>
  `;
  // clang-format on
}

export class RequestHeaderSection extends UI.Widget.Widget {
  #request: Readonly<SDK.NetworkRequest.NetworkRequest>|null = null;
  #headers: HeaderDescriptor[] = [];
  #view: View;

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

  set toReveal(toReveal: {section: NetworkForward.UIRequestLocation.UIHeaderSection, header?: string}|undefined) {
    if (!toReveal) {
      return;
    }
    if (toReveal.section === NetworkForward.UIRequestLocation.UIHeaderSection.REQUEST) {
      this.#headers.filter(header => header.name === toReveal.header?.toLowerCase()).forEach(header => {
        header.highlight = true;
      });
    }

    this.requestUpdate();
  }

  set request(request: Readonly<SDK.NetworkRequest.NetworkRequest>) {
    this.#request = request;
    this.#headers = this.#request.requestHeaders().map(header => ({
                                                         name: Platform.StringUtilities.toLowerCaseString(header.name),
                                                         value: header.value,
                                                         valueEditable: EditingAllowedStatus.FORBIDDEN,
                                                       }));
    this.#headers.sort((a, b) => Platform.StringUtilities.compare(a.name, b.name));
    this.requestUpdate();
  }

  override performUpdate(): void {
    if (!this.#request) {
      return;
    }
    this.#view(
        {
          headers: this.#headers,
          isProvisionalHeaders: this.#request.requestHeadersText() === undefined,
          isRequestCached: this.#request.cached() || this.#request.cachedInMemory(),
        },
        undefined, this.contentElement);
  }
}
