// 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 { assert } from 'chrome://resources/js/assert.js';
import { CustomElement } from 'chrome://resources/js/custom_element.js';
import { clamp, createEl, setFormattedClipboardForMl, signalNames } from '../omnibox_util.js';
import sheet from './ml_calculator.css' with { type: 'css' };
import { getTemplate } from './ml_calculator.html.js';
export class MlCalculatorElement extends CustomElement {
    mlBrowserProxy_;
    signalInputs;
    static get template() {
        return getTemplate();
    }
    constructor() {
        super();
        this.shadowRoot.adoptedStyleSheets = [sheet];
    }
    connectedCallback() {
        this.signalInputs = signalNames.map(signalName => {
            const label = createEl('label', this.getRequiredElement('#signals'), ['input-row'], signalName + ': ');
            const input = createEl('input', label);
            input.type = 'number';
            input.placeholder = 'null';
            input.addEventListener('input', () => this.update());
            return input;
        });
        this.getRequiredElement('#copy').addEventListener('click', async () => {
            const promise = setFormattedClipboardForMl({ score: this.score }, this.signals, window.location.href, await this.mlBrowserProxy_.modelVersion);
            this.dispatchEvent(new CustomEvent('copied', { detail: promise }));
        });
        this.getRequiredElement('#clear').addEventListener('click', () => {
            this.signalInputs.forEach(el => el.value = el.placeholder);
            this.update();
        });
        try {
            const urlSignals = new URLSearchParams(window.location.search).get('signals');
            if (urlSignals) {
                this.signals =
                    MlCalculatorElement.parseSignalStrings(urlSignals.split(','));
            }
        }
        catch (e) {
        }
    }
    set mlBrowserProxy(mlBrowserProxy) {
        this.mlBrowserProxy_ = mlBrowserProxy;
        mlBrowserProxy.modelVersion.then(version => {
            createEl('a', this.getRequiredElement('#version'), [], version.string)
                .href = version.url;
        });
        this.update();
    }
    static parseSignalStrings(signalStrings) {
        assert(signalStrings.length === signalNames.length);
        return Object.fromEntries(signalStrings
            .map(str => {
            // Handle `''` and `null`; otherwise `Number()` would convert them
            // to `0`.
            if (!str) {
                return null;
            }
            const num = Number(str);
            return Number.isNaN(num) ?
                null :
                clamp(Math.floor(num), -(2 ** 31), 2 ** 31 - 1);
        })
            .map((signal, i) => [signalNames[i], signal]));
    }
    get signals() {
        return MlCalculatorElement.parseSignalStrings(this.signalInputs.map(input => input.value));
    }
    set signals(signals) {
        // Signals can be numbers, booleans, or null.
        Object.values(signals).forEach((signal, i) => this.signalInputs[i].value =
            signal === null ? '' : String(Number(signal)));
        this.update();
    }
    get score() {
        return Number(this.getRequiredElement('#score').textContent);
    }
    set score(score) {
        this.getRequiredElement('#score').textContent = String(score);
    }
    async update() {
        if (!this.mlBrowserProxy_) {
            return;
        }
        this.signalInputs.forEach(input => input.classList.toggle('empty', !!input.textContent));
        this.score = await this.mlBrowserProxy_.makeMlRequest(this.signals);
        window.history.replaceState(null, '', `?signals=${Object.values(this.signals)}`);
        this.dispatchEvent(new CustomEvent('updated'));
    }
}
customElements.define('ml-calculator', MlCalculatorElement);
