// Copyright 2023 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/components/adorners/adorners.js';
import '../../ui/legacy/components/data_grid/data_grid.js';
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as AutofillManager from '../../models/autofill_manager/autofill_manager.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 autofillViewStyles from './autofillView.css.js';
const { html, render, Directives: { styleMap } } = Lit;
const { FillingStrategy } = Protocol.Autofill;
const { bindToSetting } = UI.UIUtils;
const UIStrings = {
    /**
     * @description Text shown when there is no data on autofill available.
     */
    noAutofill: 'No autofill detected',
    /**
     * @description Explanation for how to populate the autofill panel with data. Shown when there is
     * no data available.
     */
    toStartDebugging: 'To start debugging autofill, use Chrome\'s autofill menu to fill an address form.',
    /**
     * @description Column header for column containing form field values
     */
    value: 'Value',
    /**
     * @description Column header for column containing the predicted autofill categories
     */
    predictedAutofillValue: 'Predicted autofill value',
    /**
     * @description Column header for column containing the name/label/id of form fields
     */
    formField: 'Form field',
    /**
     * @description Tooltip for an adorner for form fields which have an autocomplete attribute
     * (http://go/mdn/HTML/Attributes/autocomplete)
     */
    autocompleteAttribute: 'Autocomplete attribute',
    /**
     * @description Abbreviation of 'attribute'. Text content of an adorner for form fields which
     * have an autocomplete attribute (http://go/mdn/HTML/Attributes/autocomplete)
     */
    attr: 'attr',
    /**
     * @description Tooltip for an adorner for form fields which don't have an autocomplete attribute
     * (http://go/mdn/HTML/Attributes/autocomplete) and for which Chrome used heuristics to deduce
     * the form field's autocomplete category.
     */
    inferredByHeuristics: 'Inferred by heuristics',
    /**
     * @description Abbreviation of 'heuristics'. Text content of an adorner for form fields which
     * don't have an autocomplete attribute (http://go/mdn/HTML/Attributes/autocomplete) and for
     * which Chrome used heuristics to deduce the form field's autocomplete category.
     */
    heur: 'heur',
    /**
     * @description Label for checkbox in the Autofill panel. If checked, this panel will open
     * automatically whenever a form is being autofilled.
     */
    autoShow: 'Automatically open this panel',
    /**
     * @description Label for checkbox in the Autofill panel. If checked, test addresses will be added to the Autofill popup.
     */
    showTestAddressesInAutofillMenu: 'Show test addresses in autofill menu',
    /**
     * @description Tooltip text for a checkbox label in the Autofill panel. If checked, this panel
     * will open automatically whenever a form is being autofilled.
     */
    autoShowTooltip: 'Open the autofill panel automatically when an autofill activity is detected.',
    /**
     * @description Aria text for the section of the autofill view containing a preview of the autofilled address.
     */
    addressPreview: 'Address preview',
    /**
     * @description Aria text for the section of the autofill view containing the info about the autofilled form fields.
     */
    formInspector: 'Form inspector',
    /**
     * @description Link text for a hyperlink to more documentation
     */
    learnMore: 'Learn more',
    /**
     * @description Link text for a hyperlink to webpage for leaving user feedback
     */
    sendFeedback: 'Send feedback',
};
const AUTOFILL_INFO_URL = 'https://goo.gle/devtools-autofill-panel';
const AUTOFILL_FEEDBACK_URL = 'https://crbug.com/329106326';
const str_ = i18n.i18n.registerUIStrings('panels/autofill/AutofillView.ts', UIStrings);
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const DEFAULT_VIEW = (input, _output, target) => {
    const renderAddress = () => {
        const createSpan = (startIndex, endIndex) => {
            const textContentLines = input.address.substring(startIndex, endIndex).split('\n');
            const templateLines = textContentLines.map((line, i) => i === textContentLines.length - 1 ? line : html `${line}<br>`);
            const hasMatches = input.matches.some(match => match.startIndex <= startIndex && match.endIndex > startIndex);
            if (!hasMatches) {
                return html `<span>${templateLines}</span>`;
            }
            const spanClasses = Lit.Directives.classMap({
                'matches-filled-field': hasMatches,
                highlighted: input.highlightedMatches.some(match => match.startIndex <= startIndex && match.endIndex > startIndex),
            });
            // Disabled until https://crbug.com/1079231 is fixed.
            // clang-format off
            return html `
        <span class=${spanClasses}
              jslog=${VisualLogging.item('matched-address-item').track({ hover: true, resize: true })}
              @mouseenter=${() => input.onHighlightMatchesInAddress(startIndex)}
              @mouseleave=${input.onClearHighlightedMatches}>
          ${templateLines}
        </span>`;
            // clang-format on
        };
        // Split the address string into multiple spans. Each span is connected to
        // 0 or more matches. This allows highlighting the corresponding grid rows
        // when hovering over a span. And vice versa finding the corresponding
        // spans to highlight when hovering over a grid line.
        const spans = [];
        const matchIndices = new Set([0, input.address.length]);
        for (const match of input.matches) {
            matchIndices.add(match.startIndex);
            matchIndices.add(match.endIndex);
        }
        const sortedMatchIndices = Array.from(matchIndices).sort((a, b) => a - b);
        for (let i = 0; i < sortedMatchIndices.length - 1; i++) {
            spans.push(createSpan(sortedMatchIndices[i], sortedMatchIndices[i + 1]));
        }
        return html `
      <div class="address">
        ${spans}
      </div>
    `;
    };
    const renderFilledFields = () => {
        const highlightedGridRows = new Set(input.highlightedMatches.map(match => match.filledFieldIndex));
        // Disabled until https://crbug.com/1079231 is fixed.
        // clang-format off
        return html `
      <div class="grid-wrapper" role="region" aria-label=${i18nString(UIStrings.formInspector)}>
        <devtools-data-grid striped
                            class="filled-fields-grid">
          <table>
            <tr>
              <th id="name" weight="50" sortable>${i18nString(UIStrings.formField)}</th>
              <th id="autofill-type" weight="50" sortable>${i18nString(UIStrings.predictedAutofillValue)}</th>
              <th id="value" weight="50" sortable>${i18nString(UIStrings.value)}</th>
            </tr>
            ${input.filledFields.map((field, index) => html `
                <tr style=${styleMap({
            'font-family': 'var(--monospace-font-family)',
            'font-size': 'var(--monospace-font-size)',
            'background-color': highlightedGridRows.has(index) ? 'var(--sys-color-state-hover-on-subtle)' : null
        })}
                    @mouseenter=${() => input.onHighlightMatchesInFilledFiels(index)}
                    @mouseleave=${input.onClearHighlightedMatches}>
                  <td>${field.name || `#${field.id}`} (${field.htmlType})</td>
                  <td>
                      ${field.autofillType}
                      ${field.fillingStrategy === "autocompleteAttribute" /* FillingStrategy.AutocompleteAttribute */ ?
            html `<devtools-adorner .name=${field.fillingStrategy} title=${i18nString(UIStrings.autocompleteAttribute)}>
                              <span>${i18nString(UIStrings.attr)}</span>
                            </devtools-adorner>` :
            field.fillingStrategy === "autofillInferred" /* FillingStrategy.AutofillInferred */ ?
                html `<devtools-adorner .name=${field.fillingStrategy} title=${i18nString(UIStrings.inferredByHeuristics)}>
                              <span>${i18nString(UIStrings.heur)}</span>
                            </devtools-adorner>` :
                Lit.nothing}
                  </td>
                  <td>"${field.value}"</td>
                </tr>`)}
          </table>
        </devtools-data-grid>
      </div>
    `;
        // clang-format on
    };
    if (!input.address && !input.filledFields.length) {
        // Disabled until https://crbug.com/1079231 is fixed.
        // clang-format off
        render(html `
        <style>${autofillViewStyles}</style>
        <style>${UI.inspectorCommonStyles}</style>
        <main>
          <div class="top-left-corner">
            <devtools-checkbox
                ${bindToSetting(input.showTestAddressesInAutofillMenuSetting)}
                title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}>
              ${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
            </devtools-checkbox>
            <devtools-checkbox
                ${bindToSetting(input.autoOpenViewSetting)}
                title=${i18nString(UIStrings.autoShowTooltip)}>
              ${i18nString(UIStrings.autoShow)}
            </devtools-checkbox>
            <devtools-link href=${AUTOFILL_FEEDBACK_URL} class="feedback link" jslogcontext="feedback">${i18nString(UIStrings.sendFeedback)}</devtools-link>
          </div>
          <div class="placeholder-container" jslog=${VisualLogging.pane('autofill-empty')}>
            <div class="empty-state">
              <span class="empty-state-header">${i18nString(UIStrings.noAutofill)}</span>
              <div class="empty-state-description">
                <span>${i18nString(UIStrings.toStartDebugging)}</span>
                <devtools-link href=${AUTOFILL_INFO_URL} class="link" jslogcontext="learn-more">${i18nString(UIStrings.learnMore)}</devtools-link>
              </div>
            </div>
          </div>
        </main>
      `, target);
        // clang-format on
        return;
    }
    // Disabled until https://crbug.com/1079231 is fixed.
    // clang-format off
    render(html `
      <style>${autofillViewStyles}</style>
      <style>${UI.inspectorCommonStyles}</style>
      <main>
        <div class="content-container" jslog=${VisualLogging.pane('autofill')}>
          <div class="right-to-left" role="region" aria-label=${i18nString(UIStrings.addressPreview)}>
            <div class="header">
              <div class="label-container">
                <devtools-checkbox
                    ${bindToSetting(input.showTestAddressesInAutofillMenuSetting)}
                    title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}>
                  ${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
                </devtools-checkbox>
              </div>
              <div class="label-container">
                <devtools-checkbox
                    ${bindToSetting(input.autoOpenViewSetting)}
                    title=${i18nString(UIStrings.autoShowTooltip)}>
                  ${i18nString(UIStrings.autoShow)}
                </devtools-checkbox>
              </div>
              <devtools-link href=${AUTOFILL_FEEDBACK_URL} class="feedback link" jslogcontext="feedback">${i18nString(UIStrings.sendFeedback)}</devtools-link>
            </div>
            ${renderAddress()}
          </div>
          ${renderFilledFields()}
        </div>
      </main>
    `, target);
    // clang-format on
};
export class AutofillView extends UI.Widget.VBox {
    #view;
    #autofillManager;
    #autoOpenViewSetting = Common.Settings.Settings.instance().createSetting('auto-open-autofill-view-on-event', true);
    #showTestAddressesInAutofillMenuSetting;
    #address = '';
    #filledFields = [];
    #matches = [];
    #highlightedMatches = [];
    constructor(autofillManager = AutofillManager.AutofillManager.AutofillManager.instance(), view = DEFAULT_VIEW) {
        super({ useShadowDom: true });
        this.#autofillManager = autofillManager;
        this.#view = view;
        this.#showTestAddressesInAutofillMenuSetting =
            Common.Settings.Settings.instance().createSetting('show-test-addresses-in-autofill-menu-on-event', false);
    }
    wasShown() {
        super.wasShown();
        const formFilledEvent = this.#autofillManager.getLastFilledAddressForm();
        if (formFilledEvent) {
            ({
                address: this.#address,
                filledFields: this.#filledFields,
                matches: this.#matches,
            } = formFilledEvent);
        }
        this.#autofillManager.addEventListener("AddressFormFilled" /* AutofillManager.AutofillManager.Events.ADDRESS_FORM_FILLED */, this.#onAddressFormFilled, this);
        SDK.TargetManager.TargetManager.instance().addModelListener(SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.PrimaryPageChanged, this.#onPrimaryPageChanged, this);
        this.requestUpdate();
    }
    willHide() {
        SDK.TargetManager.TargetManager.instance().removeModelListener(SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.PrimaryPageChanged, this.#onPrimaryPageChanged, this);
        this.#autofillManager.removeEventListener("AddressFormFilled" /* AutofillManager.AutofillManager.Events.ADDRESS_FORM_FILLED */, this.#onAddressFormFilled, this);
        super.willHide();
    }
    #onPrimaryPageChanged() {
        this.#address = '';
        this.#filledFields = [];
        this.#matches = [];
        this.#highlightedMatches = [];
        this.requestUpdate();
    }
    async #onAddressFormFilled({ data }) {
        if (this.#autoOpenViewSetting.get()) {
            await UI.ViewManager.ViewManager.instance().showView('autofill-view');
            Host.userMetrics.actionTaken(Host.UserMetrics.Action.AutofillReceivedAndTabAutoOpened);
        }
        else {
            Host.userMetrics.actionTaken(Host.UserMetrics.Action.AutofillReceived);
        }
        this.#address = data.address;
        this.#filledFields = data.filledFields;
        this.#matches = data.matches;
        this.#highlightedMatches = [];
        this.requestUpdate();
    }
    performUpdate() {
        const onHighlightMatchesInAddress = (startIndex) => {
            this.#highlightedMatches =
                this.#matches.filter(match => match.startIndex <= startIndex && match.endIndex > startIndex);
            this.requestUpdate();
        };
        const onHighlightMatchesInFilledFiels = (rowIndex) => {
            this.#autofillManager.highlightFilledField(this.#filledFields[rowIndex]);
            this.#highlightedMatches = this.#matches.filter(match => match.filledFieldIndex === rowIndex);
            this.requestUpdate();
        };
        const onClearHighlightedMatches = () => {
            this.#autofillManager.clearHighlightedFilledFields();
            this.#highlightedMatches = [];
            this.requestUpdate();
        };
        const input = {
            autoOpenViewSetting: this.#autoOpenViewSetting,
            showTestAddressesInAutofillMenuSetting: this.#showTestAddressesInAutofillMenuSetting,
            address: this.#address,
            filledFields: this.#filledFields,
            matches: this.#matches,
            highlightedMatches: this.#highlightedMatches,
            onHighlightMatchesInAddress,
            onHighlightMatchesInFilledFiels,
            onClearHighlightedMatches,
        };
        const output = undefined;
        this.#view(input, output, this.contentElement);
    }
}
//# sourceMappingURL=AutofillView.js.map