// 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 './ink_text_box.js';
import { assert } from 'chrome://resources/js/assert.js';
import { EventTracker } from 'chrome://resources/js/event_tracker.js';
import { CrLitElement } from 'chrome://resources/lit/v3_0/lit.rollup.js';
import { Ink2Manager } from '../ink2_manager.js';
import { pageToScreenCoordinates } from '../ink_text_annotation_utils.js';
import { getCss } from './ink_text_annotations.css.js';
import { getHtml } from './ink_text_annotations.html.js';
import { TextBoxState } from './ink_text_box.js';
export class InkTextAnnotationsElement extends CrLitElement {
    static get is() {
        return 'ink-text-annotations';
    }
    static get styles() {
        return getCss();
    }
    render() {
        return getHtml.bind(this)();
    }
    static get properties() {
        return {
            viewport: { type: Object },
            activeAnnotation_: { type: Object },
            activePageDimensions_: { type: Object },
            placeholders_: { type: Array },
        };
    }
    #viewport_accessor_storage = null;
    get viewport() { return this.#viewport_accessor_storage; }
    set viewport(value) { this.#viewport_accessor_storage = value; }
    #activeAnnotation__accessor_storage = null;
    get activeAnnotation_() { return this.#activeAnnotation__accessor_storage; }
    set activeAnnotation_(value) { this.#activeAnnotation__accessor_storage = value; }
    #activePageDimensions__accessor_storage = null;
    get activePageDimensions_() { return this.#activePageDimensions__accessor_storage; }
    set activePageDimensions_(value) { this.#activePageDimensions__accessor_storage = value; }
    #placeholders__accessor_storage = [];
    get placeholders_() { return this.#placeholders__accessor_storage; }
    set placeholders_(value) { this.#placeholders__accessor_storage = value; }
    annotations_ = [];
    eventTracker_ = new EventTracker();
    connectedCallback() {
        super.connectedCallback();
        const manager = Ink2Manager.getInstance();
        this.eventTracker_.add(manager, 'annotations-updated', () => this.updateAnnotations_());
        this.eventTracker_.add(manager, 'initialize-text-box', (e) => this.onInitializeTextBox_(e.detail));
        this.updateAnnotations_();
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.eventTracker_.removeAll();
    }
    viewportChanged() {
        this.updatePlaceholders_();
        this.$.textBox.viewportChanged();
    }
    updateAnnotations_() {
        const manager = Ink2Manager.getInstance();
        const allAnnotations = [];
        const sortedPages = Array.from(manager.annotations.keys()).sort((a, b) => a - b);
        for (const page of sortedPages) {
            const pageAnnotationsMap = manager.annotations.get(page);
            if (!pageAnnotationsMap) {
                continue;
            }
            const pageAnnotations = Array.from(pageAnnotationsMap.values());
            // Sort visually: top-to-bottom, then left-to-right
            pageAnnotations.sort((a, b) => {
                if (a.textBoxRect.locationY !== b.textBoxRect.locationY) {
                    return a.textBoxRect.locationY - b.textBoxRect.locationY;
                }
                return a.textBoxRect.locationX - b.textBoxRect.locationX;
            });
            allAnnotations.push(...pageAnnotations);
        }
        this.annotations_ = allAnnotations;
        this.updatePlaceholders_();
    }
    updatePlaceholders_() {
        assert(this.viewport);
        this.placeholders_ = this.annotations_.map(annotation => {
            const screenRect = pageToScreenCoordinates(annotation.pageIndex, annotation.textBoxRect, this.viewport);
            return {
                screenRect,
                label: annotation.text,
                rotations: (this.viewport.getClockwiseRotations() +
                    annotation.textOrientation) %
                    4,
                zIndex: annotation.id,
            };
        });
    }
    getStyles_(placeholder) {
        return `
      --left: ${placeholder.screenRect.locationX}px;
      --top: ${placeholder.screenRect.locationY}px;
      --width: ${placeholder.screenRect.width}px;
      --height: ${placeholder.screenRect.height}px;
      z-index: ${placeholder.zIndex};
    `;
    }
    onPlaceholderFocus_(e) {
        const currentTarget = e.currentTarget;
        const index = Number(currentTarget.dataset['index']);
        const placeholder = this.placeholders_[index];
        assert(placeholder);
        this.scrollToShowTextBox_(placeholder.screenRect);
    }
    async onPlaceholderClick_(e) {
        const index = Number(e.currentTarget.dataset['index']);
        await this.activateAnnotationByIndex_(index);
    }
    async onPlaceholderKeydown_(e) {
        if (e.key !== 'Enter' && e.key !== ' ') {
            return;
        }
        e.preventDefault();
        const index = Number(e.currentTarget.dataset['index']);
        await this.activateAnnotationByIndex_(index);
    }
    async activateAnnotationByIndex_(index) {
        // Grab the annotation first, since committing may update the annotations
        // list and make `index` refer to a different annotation than intended.
        const annotation = this.annotations_[index];
        assert(annotation);
        if (this.activeAnnotation_) {
            // The requested annotation is already active. This also ensures that if
            // committing deletes an annotation, it isn't the one being activated.
            if (this.activeAnnotation_.id === annotation.id) {
                return;
            }
            await this.$.textBox.commitTextAnnotation();
        }
        assert(this.viewport);
        // Convert box to screen coordinates.
        const screenRect = pageToScreenCoordinates(annotation.pageIndex, annotation.textBoxRect, this.viewport);
        // Create a copy of the annotation with screen coordinates for the textbox.
        const annotationToActivate = structuredClone(annotation);
        annotationToActivate.textBoxRect = screenRect;
        // Notify the backend.
        Ink2Manager.getInstance().reactivateTextAnnotation(annotation);
        this.activeAnnotation_ = annotationToActivate;
        this.activePageDimensions_ =
            this.viewport.getPageScreenRect(annotation.pageIndex);
    }
    commitActiveAnnotation() {
        return this.$.textBox.commitTextAnnotation();
    }
    blurActiveAnnotation() {
        this.$.textBox.blur();
    }
    onTextBoxStateChanged_(e) {
        if (e.detail === TextBoxState.INACTIVE) {
            this.activeAnnotation_ = null;
            this.activePageDimensions_ = null;
        }
        this.fire('state-changed', e.detail);
    }
    async onInitializeTextBox_(data) {
        if (this.activeAnnotation_) {
            await this.$.textBox.commitTextAnnotation();
        }
        this.activeAnnotation_ = data.annotation;
        this.activePageDimensions_ = data.pageDimensions;
    }
    onTextboxFocused_(e) {
        this.scrollToShowTextBox_(e.detail);
    }
    scrollToShowTextBox_(textBoxRect) {
        // The viewport handles scrolling, so prevent the browser from
        // auto-scrolling.
        this.$.container.scrollTop = 0;
        this.$.container.scrollLeft = 0;
        this.scrollTop = 0;
        this.scrollLeft = 0;
        assert(this.viewport);
        const viewportPosition = this.viewport.position;
        const viewportSize = this.viewport.size;
        let scrollX;
        let scrollY;
        if (textBoxRect.locationX < 0 ||
            textBoxRect.locationX + textBoxRect.width > viewportSize.width) {
            // Adjusting by 10% of viewport, rather than putting the text box on the
            // exact edge of the viewport.
            scrollX = viewportPosition.x + textBoxRect.locationX -
                Math.floor(viewportSize.width / 10);
        }
        if (textBoxRect.locationY < 0 ||
            textBoxRect.locationY + textBoxRect.height > viewportSize.height) {
            // Adjusting by 10% of viewport, rather than putting the text box on the
            // exact edge of the viewport.
            scrollY = viewportPosition.y + textBoxRect.locationY -
                Math.floor(viewportSize.height / 10);
        }
        if (scrollX !== undefined || scrollY !== undefined) {
            // TODO(crbug.com/40218278): Re-enable smooth scrolling for all codepaths.
            this.viewport.scrollTo({
                x: scrollX,
                y: scrollY,
            });
        }
    }
}
customElements.define(InkTextAnnotationsElement.is, InkTextAnnotationsElement);
