// 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.
/* eslint-disable rulesdir/no-lit-render-outside-of-view */

import '../../../ui/components/icon_button/icon_button.js';

import * as Host from '../../../core/host/host.js';
import * as i18n from '../../../core/i18n/i18n.js';
import * as Platform from '../../../core/platform/platform.js';
import * as Buttons from '../../../ui/components/buttons/buttons.js';
import * as Input from '../../../ui/components/input/input.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 protocolHandlersViewStyles from './protocolHandlersView.css.js';

const {html} = Lit;

const PROTOCOL_DOCUMENT_URL = 'https://web.dev/url-protocol-handler/';
const UIStrings = {
  /**
   * @description Status message for when protocol handlers are detected in the manifest
   * @example {protocolhandler/manifest.json} PH1
   */
  protocolDetected:
      'Found valid protocol handler registration in the {PH1}. With the app installed, test the registered protocols.',
  /**
   * @description Status message for when protocol handlers are not detected in the manifest
   * @example {protocolhandler/manifest.json} PH1
   */
  protocolNotDetected:
      'Define protocol handlers in the {PH1} to register your app as a handler for custom protocols when your app is installed.',
  /**
   * @description Text wrapping a link pointing to more information on handling protocol handlers
   * @example {https://example.com/} PH1
   */
  needHelpReadOur: 'Need help? Read {PH1}.',
  /**
   * @description Link text for more information on URL protocol handler registrations for PWAs
   */
  protocolHandlerRegistrations: 'URL protocol handler registration for PWAs',
  /**
   * @description In text hyperlink to the PWA manifest
   */
  manifest: 'manifest',
  /**
   * @description Text for test protocol button
   */
  testProtocol: 'Test protocol',
  /**
   * @description Aria text for screen reader to announce they can select a protocol handler in the dropdown
   */
  dropdownLabel: 'Select protocol handler',
  /**
   * @description Aria text for screen reader to announce they can enter query parameters or endpoints into the textbox
   */
  textboxLabel: 'Query parameter or endpoint for protocol handler',
  /**
   * @description Placeholder for textbox input field, rest of the URL of protocol to test.
   */
  textboxPlaceholder: 'Enter URL',
} as const;

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

interface HTMLSelectElementEvent extends Event {
  target: HTMLSelectElement;
}

interface HTMLInputElementEvent extends Event {
  target: HTMLInputElement;
}

export interface ProtocolHandler {
  protocol: string;
  url: string;
}

export interface ProtocolHandlersData {
  protocolHandlers: ProtocolHandler[];
  manifestLink: Platform.DevToolsPath.UrlString;
}

export class ProtocolHandlersView extends HTMLElement {
  readonly #shadow = this.attachShadow({mode: 'open'});
  #protocolHandlers: ProtocolHandler[] = [];
  #manifestLink: Platform.DevToolsPath.UrlString = Platform.DevToolsPath.EmptyUrlString;
  #selectedProtocolState = '';
  #queryInputState = '';

  set data(data: ProtocolHandlersData) {
    const isNewManifest = this.#manifestLink !== data.manifestLink;
    this.#protocolHandlers = data.protocolHandlers;
    this.#manifestLink = data.manifestLink;
    if (isNewManifest) {
      this.#update();
    }
  }

  #update(): void {
    this.#queryInputState = '';
    this.#selectedProtocolState = this.#protocolHandlers[0]?.protocol ?? '';
    this.#render();
  }

  #renderStatusMessage(): Lit.TemplateResult {
    const manifestInTextLink =
        UI.XLink.XLink.create(this.#manifestLink, i18nString(UIStrings.manifest), undefined, undefined, 'manifest');
    const statusString = this.#protocolHandlers.length > 0 ? UIStrings.protocolDetected : UIStrings.protocolNotDetected;
    // clang-format off
    return html`
    <div class="protocol-handlers-row status">
            <devtools-icon class="inline-icon"
                           name=${this.#protocolHandlers.length > 0 ? 'check-circle' : 'info'}>
            </devtools-icon>
            ${i18n.i18n.getFormatLocalizedString(str_, statusString, {
      PH1: manifestInTextLink,
    })}
    </div>
    `;
    // clang-format on
  }

  #renderProtocolTest(): Lit.LitTemplate {
    if (this.#protocolHandlers.length === 0) {
      return Lit.nothing;
    }
    const protocolOptions =
        this.#protocolHandlers.filter(p => p.protocol)
            .map(p => html`<option value=${p.protocol} jslog=${VisualLogging.item(p.protocol).track({
                   click: true,
                 })}>${p.protocol}://</option>`);
    return html`
       <div class="protocol-handlers-row">
        <select class="protocol-select" @change=${this.#handleProtocolSelect} aria-label=${
        i18nString(UIStrings.dropdownLabel)}>
           ${protocolOptions}
        </select>
        <input .value=${this.#queryInputState} class="devtools-text-input" type="text" @change=${
        this.#handleQueryInputChange} aria-label=${i18nString(UIStrings.textboxLabel)}
        placeholder=${i18nString(UIStrings.textboxPlaceholder)} />
        <devtools-button .variant=${Buttons.Button.Variant.PRIMARY} @click=${this.#handleTestProtocolClick}>
            ${i18nString(UIStrings.testProtocol)}
        </devtools-button>
        </div>
      `;
  }

  #handleProtocolSelect = (evt: HTMLSelectElementEvent): void => {
    this.#selectedProtocolState = evt.target.value;
  };

  #handleQueryInputChange = (evt: HTMLInputElementEvent): void => {
    this.#queryInputState = evt.target.value;
    this.#render();
  };

  #handleTestProtocolClick = (): void => {
    const protocolURL = `${this.#selectedProtocolState}://${this.#queryInputState}` as Platform.DevToolsPath.UrlString;
    Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(protocolURL);
    Host.userMetrics.actionTaken(Host.UserMetrics.Action.CaptureTestProtocolClicked);
  };

  #render(): void {
    const protocolDocLink = UI.XLink.XLink.create(
        PROTOCOL_DOCUMENT_URL, i18nString(UIStrings.protocolHandlerRegistrations), undefined, undefined, 'learn-more');
    // inspectorCommonStyles is used for the <select> styling that is used for the dropdown
    // clang-format off
    Lit.render(html`
      <style>${protocolHandlersViewStyles}</style>
      <style>${UI.inspectorCommonStyles}</style>
      <style>${Input.textInputStyles}</style>
      ${this.#renderStatusMessage()}
      <div class="protocol-handlers-row">
          ${i18n.i18n.getFormatLocalizedString(str_, UIStrings.needHelpReadOur, {PH1: protocolDocLink})}
      </div>
      ${this.#renderProtocolTest()}
    `, this.#shadow, {host: this});
    // clang-format on
  }
}

customElements.define('devtools-protocol-handlers-view', ProtocolHandlersView);

declare global {
  interface HTMLElementTagNameMap {
    'devtools-protocol-handlers-view': ProtocolHandlersView;
  }
}
