// 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 '//resources/cr_components/searchbox/searchbox_dropdown.js';
import '//resources/cr_components/searchbox/searchbox_input.js';
import '//resources/cr_components/searchbox/searchbox_compose_button.js';
import '//resources/cr_components/search/animated_glow.js';
import '//resources/cr_components/composebox/composebox_file_inputs.js';
import '//resources/cr_components/composebox/contextual_entrypoint_and_menu.js';
import './profile_icon.js';
import { ContextType, GlifAnimationState, recordContextAdditionMethod, recordContextualElementClickedMetric, TabSuggestionsState } from '//resources/cr_components/composebox/common.js';
import { GlowAnimationState } from '//resources/cr_components/search/constants.js';
import { DragAndDropHandler } from '//resources/cr_components/search/drag_drop_handler.js';
import { SearchboxBrowserProxy } from '//resources/cr_components/searchbox/searchbox_browser_proxy.js';
import { SearchboxMixin } from '//resources/cr_components/searchbox/searchbox_mixin.js';
import { I18nMixinLit } from '//resources/cr_elements/i18n_mixin_lit.js';
import { WebUiListenerMixinLit } from '//resources/cr_elements/web_ui_listener_mixin_lit.js';
import { loadTimeData } from '//resources/js/load_time_data.js';
import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js';
import { DriveDisclaimerStatus } from '//resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js';
import { ModelMode, ToolMode } from '//resources/mojo/components/omnibox/composebox/composebox_query.mojom-webui.js';
import { getCss } from './omnibox.css.js';
import { getHtml } from './omnibox.html.js';
// Note: Copied from omnibox_popup_searchbox.ts.
//       I18nMixinLit may eventually be moved to SearchboxMixin.
const OmniboxEverywhereOmniboxElementBase = SearchboxMixin(I18nMixinLit(WebUiListenerMixinLit(CrLitElement)));
export class OmniboxEverywhereOmniboxElement extends OmniboxEverywhereOmniboxElementBase {
    static get is() {
        return 'omnibox-everywhere-omnibox';
    }
    static get styles() {
        return getCss();
    }
    render() {
        return getHtml.bind(this)();
    }
    static get properties() {
        return {
            placeholderText: {
                type: String,
                reflect: true,
                notify: true,
            },
            searchboxChromeRefreshTheming: {
                type: Boolean,
                reflect: true,
            },
            searchboxSteadyStateShadow: {
                type: Boolean,
                reflect: true,
            },
            searchboxIcon_: { type: String },
            searchboxVoiceSearchEnabled_: {
                type: Boolean,
                reflect: true,
            },
            searchboxLensSearchEnabled_: {
                type: Boolean,
                reflect: true,
            },
            useWebkitSearchIcons_: {
                type: Boolean,
                reflect: true,
            },
            animationState: {
                type: String,
                reflect: true,
            },
            inVoiceSearchMode: {
                type: Boolean,
                reflect: true,
            },
            composeButtonEnabled: { type: Boolean, reflect: true },
            profileAvatarUrl_: { type: String },
            isFuseboxEnabled: { type: Boolean, reflect: true },
            hasUserInput_: { type: Boolean },
            ntpRealboxDynamicAiModeButtonEnabled_: { type: Boolean },
            contextMenuGlifAnimationState: {
                type: String,
                reflect: true,
            },
            inputState_: { type: Object },
            tabSuggestions_: { type: Array },
            searchboxLayoutMode: { type: String },
            tabSuggestionsState_: { type: Number },
            contextManagementInComposeboxEnabled: { type: Boolean },
            isDraggingFile: {
                reflect: true,
                type: Boolean,
            },
            fileContextEnabled_: { type: Boolean },
        };
    }
    #placeholderText_accessor_storage = '';
    get placeholderText() { return this.#placeholderText_accessor_storage; }
    set placeholderText(value) { this.#placeholderText_accessor_storage = value; }
    #isDraggingFile_accessor_storage = false;
    get isDraggingFile() { return this.#isDraggingFile_accessor_storage; }
    set isDraggingFile(value) { this.#isDraggingFile_accessor_storage = value; }
    dragAndDropHandler;
    #fileContextEnabled__accessor_storage = loadTimeData.getBoolean('composeboxContextDragAndDropEnabled');
    get fileContextEnabled_() { return this.#fileContextEnabled__accessor_storage; }
    set fileContextEnabled_(value) { this.#fileContextEnabled__accessor_storage = value; }
    #searchboxChromeRefreshTheming_accessor_storage = loadTimeData.getBoolean('searchboxCr23Theming');
    get searchboxChromeRefreshTheming() { return this.#searchboxChromeRefreshTheming_accessor_storage; }
    set searchboxChromeRefreshTheming(value) { this.#searchboxChromeRefreshTheming_accessor_storage = value; }
    #searchboxSteadyStateShadow_accessor_storage = loadTimeData.getBoolean('searchboxCr23SteadyStateShadow');
    get searchboxSteadyStateShadow() { return this.#searchboxSteadyStateShadow_accessor_storage; }
    set searchboxSteadyStateShadow(value) { this.#searchboxSteadyStateShadow_accessor_storage = value; }
    #contextManagementInComposeboxEnabled_accessor_storage = false;
    get contextManagementInComposeboxEnabled() { return this.#contextManagementInComposeboxEnabled_accessor_storage; }
    set contextManagementInComposeboxEnabled(value) { this.#contextManagementInComposeboxEnabled_accessor_storage = value; }
    #searchboxIcon__accessor_storage = '//resources/cr_components/searchbox/icons/google_g.svg';
    get searchboxIcon_() { return this.#searchboxIcon__accessor_storage; }
    set searchboxIcon_(value) { this.#searchboxIcon__accessor_storage = value; }
    #searchboxVoiceSearchEnabled__accessor_storage = loadTimeData.getBoolean('searchboxVoiceSearch');
    get searchboxVoiceSearchEnabled_() { return this.#searchboxVoiceSearchEnabled__accessor_storage; }
    set searchboxVoiceSearchEnabled_(value) { this.#searchboxVoiceSearchEnabled__accessor_storage = value; }
    #searchboxLensSearchEnabled__accessor_storage = loadTimeData.getBoolean('searchboxLensSearch');
    get searchboxLensSearchEnabled_() { return this.#searchboxLensSearchEnabled__accessor_storage; }
    set searchboxLensSearchEnabled_(value) { this.#searchboxLensSearchEnabled__accessor_storage = value; }
    #useWebkitSearchIcons__accessor_storage = true;
    get useWebkitSearchIcons_() { return this.#useWebkitSearchIcons__accessor_storage; }
    set useWebkitSearchIcons_(value) { this.#useWebkitSearchIcons__accessor_storage = value; }
    #animationState_accessor_storage = GlowAnimationState.NONE;
    get animationState() { return this.#animationState_accessor_storage; }
    set animationState(value) { this.#animationState_accessor_storage = value; }
    #inVoiceSearchMode_accessor_storage = false;
    get inVoiceSearchMode() { return this.#inVoiceSearchMode_accessor_storage; }
    set inVoiceSearchMode(value) { this.#inVoiceSearchMode_accessor_storage = value; }
    #composeButtonEnabled_accessor_storage = loadTimeData.getBoolean('searchboxShowComposeEntrypoint');
    get composeButtonEnabled() { return this.#composeButtonEnabled_accessor_storage; }
    set composeButtonEnabled(value) { this.#composeButtonEnabled_accessor_storage = value; }
    #profileAvatarUrl__accessor_storage = loadTimeData.getString('profileAvatarUrl');
    get profileAvatarUrl_() { return this.#profileAvatarUrl__accessor_storage; }
    set profileAvatarUrl_(value) { this.#profileAvatarUrl__accessor_storage = value; }
    #isFuseboxEnabled_accessor_storage = loadTimeData.getBoolean('isFuseboxEnabled');
    get isFuseboxEnabled() { return this.#isFuseboxEnabled_accessor_storage; }
    set isFuseboxEnabled(value) { this.#isFuseboxEnabled_accessor_storage = value; }
    #hasUserInput__accessor_storage = false;
    get hasUserInput_() { return this.#hasUserInput__accessor_storage; }
    set hasUserInput_(value) { this.#hasUserInput__accessor_storage = value; }
    #ntpRealboxDynamicAiModeButtonEnabled__accessor_storage = loadTimeData.getBoolean('ntpRealboxDynamicAiModeButton');
    get ntpRealboxDynamicAiModeButtonEnabled_() { return this.#ntpRealboxDynamicAiModeButtonEnabled__accessor_storage; }
    set ntpRealboxDynamicAiModeButtonEnabled_(value) { this.#ntpRealboxDynamicAiModeButtonEnabled__accessor_storage = value; }
    #contextMenuGlifAnimationState_accessor_storage = GlifAnimationState.STARTED;
    get contextMenuGlifAnimationState() { return this.#contextMenuGlifAnimationState_accessor_storage; }
    set contextMenuGlifAnimationState(value) { this.#contextMenuGlifAnimationState_accessor_storage = value; }
    #inputState__accessor_storage = null;
    get inputState_() { return this.#inputState__accessor_storage; }
    set inputState_(value) { this.#inputState__accessor_storage = value; }
    #tabSuggestions__accessor_storage = [];
    get tabSuggestions_() { return this.#tabSuggestions__accessor_storage; }
    set tabSuggestions_(value) { this.#tabSuggestions__accessor_storage = value; }
    #searchboxLayoutMode_accessor_storage = loadTimeData.getString('searchboxLayoutMode');
    get searchboxLayoutMode() { return this.#searchboxLayoutMode_accessor_storage; }
    set searchboxLayoutMode(value) { this.#searchboxLayoutMode_accessor_storage = value; }
    #tabSuggestionsState__accessor_storage = TabSuggestionsState.NOT_STARTED;
    get tabSuggestionsState_() { return this.#tabSuggestionsState__accessor_storage; }
    set tabSuggestionsState_(value) { this.#tabSuggestionsState__accessor_storage = value; }
    pageHandler_;
    callbackRouter_;
    autocompleteResultChangedListenerId_ = null;
    inputStateListenerId_ = null;
    constructor() {
        super();
        const browserProxy = SearchboxBrowserProxy.getInstance();
        this.pageHandler_ = browserProxy.handler;
        this.callbackRouter_ = browserProxy.callbackRouter;
        this.dragAndDropHandler =
            new DragAndDropHandler(this, this.fileContextEnabled_);
    }
    connectedCallback() {
        super.connectedCallback();
        this.autocompleteResultChangedListenerId_ =
            this.callbackRouter_.autocompleteResultChanged.addListener(this.onAutocompleteResultChanged.bind(this));
        this.inputStateListenerId_ =
            this.callbackRouter_.onInputStateChanged.addListener((inputState) => {
                this.inputState_ = inputState;
            });
        this.pageHandler_.getInputState().then((response) => {
            this.inputState_ = response.state;
        });
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        if (this.autocompleteResultChangedListenerId_ !== null) {
            this.callbackRouter_.removeListener(this.autocompleteResultChangedListenerId_);
            this.autocompleteResultChangedListenerId_ = null;
        }
        if (this.inputStateListenerId_ !== null) {
            this.callbackRouter_.removeListener(this.inputStateListenerId_);
            this.inputStateListenerId_ = null;
        }
    }
    willUpdate(changedProperties) {
        super.willUpdate(changedProperties);
        if (changedProperties.has('searchboxChromeRefreshTheming')) {
            this.useWebkitSearchIcons_ = this.searchboxChromeRefreshTheming;
        }
    }
    firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        this.initialInputScrollHeight = this.$.input.scrollHeight;
    }
    focusInput() {
        this.$.input.focus();
    }
    setInputText(text) {
        this.$.input.setInputText(text);
    }
    getDropTarget() {
        return this;
    }
    addDroppedFiles(files) {
        this.processFiles_(files, 2 /* ComposeboxContextAddedMethod.DRAG_AND_DROP */);
    }
    //========================================================================
    // SearchboxMixin abstract method implementations
    //========================================================================
    getInputElement() {
        return this.$.input;
    }
    getDropdownElement() {
        return this.$.matches;
    }
    getWrapperElement() {
        return this.$.inputWrapper;
    }
    pageHandler() {
        return this.pageHandler_;
    }
    //========================================================================
    // Event handlers
    //========================================================================
    onInputFocusin_() {
        this.pageHandler_.onFocusChanged(true);
    }
    isInputEmpty() {
        // If this is called before first render, the input element will not exist.
        if (!this.shadowRoot?.querySelector('#input') || !this.$.input) {
            return true;
        }
        return !this.$.input.getInputValue().trim();
    }
    showVoiceAndLensButtons_(isEnabled) {
        return isEnabled && this.isInputEmpty() &&
            !(this.dropdownIsVisible && this.composeButtonEnabled);
    }
    computePlaceholderText_() {
        if (this.placeholderText) {
            return this.placeholderText;
        }
        if (this.isFuseboxEnabled) {
            return this.i18n('searchBoxHintAskOrType');
        }
        return this.i18n('searchBoxHint');
    }
    onSearchboxInputTextUpdated_(e) {
        this.hasUserInput_ = !!e.detail.value.trim();
        this.onSearchboxInputTextUpdated(e);
    }
    async onVoiceSearchButtonClick_() {
        this.animationState = GlowAnimationState.NONE;
        await this.updateComplete;
        this.animationState = GlowAnimationState.LISTENING;
        this.inVoiceSearchMode = true;
        this.dispatchEvent(new Event('open-voice-search', { bubbles: true, composed: true }));
    }
    onLensSearchClick_() {
        this.dropdownIsVisible = false;
        this.dispatchEvent(new Event('open-lens-search', { bubbles: true, composed: true }));
    }
    async onOpenDriveUpload_() {
        // Check if the user has accepted the Drive disclaimer. This handles
        // the edge case where a user sees the drive option in the menu, but
        // then revokes Drive permissions.
        const { status } = await this.pageHandler().getDriveDisclaimerStatus();
        if (status === DriveDisclaimerStatus.kRestricted) {
            return;
        }
        const { response } = await this.pageHandler().onDriveUploadClicked();
        const driveUploads = response.files.map(file => ({
            token: file.token,
            mimeType: file.mimeType,
            fileName: file.fileName,
            thumbnailUrl: file.thumbnailUrl ?? null,
            iconUrl: file.iconUrl ?? null,
        }));
        recordContextualElementClickedMetric(this.composeboxSource, 'ClassicPopup', ContextType.DRIVE);
        if (driveUploads.length > 0 || response.error !== null) {
            this.openComposebox_(driveUploads, ToolMode.kUnspecified, ModelMode.kUnspecified, response.error ?? undefined);
        }
    }
    onAddTabContext_(e) {
        const tabUpload = {
            tabId: e.detail.id,
            title: e.detail.title,
            url: e.detail.url,
            delayUpload: e.detail.delayUpload,
            origin: e.detail.origin,
        };
        recordContextualElementClickedMetric(this.composeboxSource, 'ClassicPopup', ContextType.TAB);
        this.openComposebox_([tabUpload]);
    }
    onFileChange_(e) {
        this.processFiles_(e.detail.files, 0 /* ComposeboxContextAddedMethod.CONTEXT_MENU */);
    }
    onSearchboxInputFilesPasted_(e) {
        this.processFiles_(e.detail.files, 1 /* ComposeboxContextAddedMethod.COPY_PASTE */);
    }
    processFiles_(files, contextAdditionMethod) {
        if (!files || files.length === 0) {
            return;
        }
        recordContextAdditionMethod(contextAdditionMethod, 'OmniboxEverywhere');
        this.openComposebox_(Array.from(files, (file) => ({ file })));
    }
    openComposebox_(uploads = [], mode = ToolMode.kUnspecified, model = ModelMode.kUnspecified, error) {
        this.fire('open-composebox', {
            text: this.$.input.inputElement.value,
            files: uploads,
            mode: mode,
            model: model,
            error: error,
            smartTabSharingActive: false,
        });
    }
    async openComposeboxWithMode_(mode, model) {
        this.animationState = GlowAnimationState.NONE;
        await this.updateComplete;
        this.animationState = GlowAnimationState.LISTENING;
        setTimeout(() => {
            this.openComposebox_([], mode, model);
        }, 300);
    }
    onComposeClick_() {
        this.openComposeboxWithMode_();
    }
    onContextMenuEntrypointClick_() {
        this.pageHandler().activateMetricsFunnel('PlusButton');
    }
    async refreshTabSuggestions_(forceRefresh = false) {
        if (this.tabSuggestionsState_ === TabSuggestionsState.LOADING ||
            (this.tabSuggestionsState_ === TabSuggestionsState.LOADED &&
                !forceRefresh)) {
            return;
        }
        this.tabSuggestionsState_ = TabSuggestionsState.LOADING;
        try {
            const { tabs } = await this.pageHandler_.getRecentTabs();
            this.tabSuggestions_ = [...tabs];
            this.tabSuggestionsState_ = TabSuggestionsState.LOADED;
        }
        finally {
            if (this.tabSuggestionsState_ === TabSuggestionsState.LOADING) {
                this.tabSuggestionsState_ = TabSuggestionsState.NOT_STARTED;
            }
        }
    }
    onContextMenuOpened_() {
        this.refreshTabSuggestions_(/*forceRefresh=*/ true);
    }
    onContextMenuClosed_() {
        this.tabSuggestionsState_ = TabSuggestionsState.NOT_STARTED;
    }
    onRequestTabSuggestionsLoad() {
        this.refreshTabSuggestions_(/*forceRefresh=*/ true);
    }
    onToolClick_(e) {
        this.openComposeboxWithMode_(e.detail.toolMode);
    }
    onDeepSearchClick_() {
        this.openComposeboxWithMode_(ToolMode.kDeepSearch);
    }
    onCreateImageClick_() {
        this.openComposeboxWithMode_(ToolMode.kImageGen);
    }
    onModelClick_(e) {
        this.openComposeboxWithMode_(ToolMode.kUnspecified, e.detail.model);
    }
}
customElements.define(OmniboxEverywhereOmniboxElement.is, OmniboxEverywhereOmniboxElement);
