var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import Pango from 'gi://Pango';
import St from 'gi://St';
import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
import { ActiveState } from '../../common/constants.js';
import { enumParamSpec, flagsParamSpec, registerClass } from '../../common/gjs.js';
import { Icon } from '../../common/icons.js';
import { tryGetLinkImage, tryGetMetadata } from '../../misc/link.js';
import { BackgroundSize, ImagePreview } from '../components/contentPreview.js';
import { ClipboardItem } from './clipboardItem.js';
const SPACING = 3;
const IMAGE_SPACING = 6;
let LinkPreview = class LinkPreview extends St.Widget {
    ext;
    _metadata = null;
    _showImage = false;
    _backgroundSize = BackgroundSize.Contain;
    _orientation = Clutter.Orientation.VERTICAL;
    _topPadding = false;
    _image;
    _title;
    _description;
    _url;
    _singleUrl;
    _cancellable = new Gio.Cancellable();
    constructor(ext, url) {
        super({
            style_class: 'link-preview',
            y_expand: true,
            y_align: Clutter.ActorAlign.FILL,
        });
        this.ext = ext;
        this._title = new St.Label({ style_class: 'link-title', visible: false });
        this.add_child(this._title);
        this._description = new St.Label({ style_class: 'link-description', visible: false });
        this._description.clutter_text.line_wrap = true;
        this._description.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
        this.add_child(this._description);
        this._url = new St.Label({ style_class: 'link-url small', text: url });
        this._url.clutter_text.line_wrap = true;
        this._url.clutter_text.line_wrap_mode = Pango.WrapMode.CHAR;
        this.add_child(this._url);
        this._singleUrl = new St.Label({ style_class: 'link-url', text: url });
        this._singleUrl.clutter_text.line_wrap = true;
        this._singleUrl.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
        this.add_child(this._singleUrl);
        this.configureMetadata();
    }
    get metadata() {
        return this._metadata;
    }
    set metadata(metadata) {
        this._metadata = metadata;
        this._title.text = metadata.title ?? _('No Title');
        this._title.style_class = metadata.title ? 'link-title' : 'link-title no-title';
        this._description.text = metadata.description ?? _('No Description');
        this._description.style_class = metadata.description ? 'link-description' : 'link-description no-description';
        this.configureMetadata();
        this.notify('metadata');
    }
    get showImage() {
        return this._showImage;
    }
    set showImage(showImage) {
        if (this._showImage === showImage)
            return;
        this._showImage = showImage;
        this.configureMetadata();
        this.notify('show-image');
    }
    get backgroundSize() {
        return this._backgroundSize;
    }
    set backgroundSize(backgroundSize) {
        if (this._backgroundSize === backgroundSize)
            return;
        this._backgroundSize = backgroundSize;
        if (this._image)
            this._image.backgroundSize = backgroundSize;
        this.notify('background-size');
    }
    get orientation() {
        return this._orientation;
    }
    set orientation(orientation) {
        if (this._orientation === orientation)
            return;
        this._orientation = orientation;
        this.notify('orientation');
    }
    set active(active) {
        if (this._image)
            this._image.active = active;
        this.notify('active');
    }
    set topPadding(topPadding) {
        if (this._topPadding === topPadding)
            return;
        this._topPadding = topPadding;
        this.notify('top-padding');
    }
    configureMetadata() {
        if (this._image) {
            this._image.visible = this._showImage;
        }
        else if (this._image === undefined && this._metadata?.image && this._showImage) {
            this._image = null;
            tryGetLinkImage(this.ext, this._metadata.image, this._cancellable)
                .then((image) => {
                if (image) {
                    this._image = new ImagePreview(this.ext, image);
                    this._image.backgroundSize = this._backgroundSize;
                    this.insert_child_at_index(this._image, 0);
                }
                else {
                    this._image = null;
                }
            })
                .catch(() => { });
        }
        this._title.visible = this._metadata?.title != null || this._metadata?.description != null;
        this._description.visible = this._metadata?.title != null && this._metadata?.description != null;
        this.queue_relayout();
    }
    vfunc_get_preferred_height(for_width) {
        const [, nat0] = this._image?.visible ? this._image.get_preferred_height(for_width) : [0, 0];
        const [, nat1] = this._title.visible ? this._title.get_preferred_height(for_width) : [0, 0];
        const [min2, nat2] = this._description.visible ? this._description.get_preferred_height(for_width) : [0, 0];
        const [min3, nat3] = this._url.get_preferred_height(for_width);
        const [min4, nat4] = this._singleUrl.get_preferred_height(for_width);
        const vertical = this.orientation === Clutter.Orientation.VERTICAL;
        if (vertical && nat0 > 0) {
            const nat = nat0 + nat1 + Math.min(nat2, min2) + min3 + IMAGE_SPACING;
            return [min4, Math.max(nat, nat4)];
        }
        const nat = nat1 + Math.min(nat2, min2 * 2) + nat3 + (this._topPadding ? SPACING : 0);
        return [min4, Math.max(nat, nat4)];
    }
    vfunc_allocate(box) {
        super.vfunc_allocate(box);
        const vertical = this.orientation === Clutter.Orientation.VERTICAL;
        const width = box.get_width();
        const height = box.get_height();
        const [, nat0] = this._image?.visible ? this._image.get_preferred_height(width) : [0, 0];
        let imageWidth, x;
        if (nat0 > 0) {
            imageWidth = vertical ? width : Math.min(height, Math.floor(width / 2 - IMAGE_SPACING));
            x = vertical ? 0 : imageWidth + IMAGE_SPACING * 2;
        }
        else {
            imageWidth = 0;
            x = 0;
        }
        const [min1, nat1] = this._title.get_preferred_height(width - x);
        const [min2, nat2] = this._description.get_preferred_height(width - x);
        const [min3, nat3] = this._url.get_preferred_height(width - x);
        // Add top padding for when the header is hidden
        let spacing = this._topPadding ? SPACING : 0;
        // Set minimum height to minimum of url
        let h = min3 + spacing;
        // Title
        let h1 = 0;
        if (this._title.visible) {
            if (h + nat1 <= height) {
                h1 = nat1;
            }
            else if (h + min1 <= height) {
                h1 = min1;
            }
        }
        this._title.opacity = h1 > 0 ? 255 : 0;
        h += h1;
        // Description
        let h2 = 0;
        if (this._description.visible) {
            if (vertical && nat0 > 0 && h + min2 <= height) {
                h2 = min2;
            }
            else if (h + min2 * 2 <= height) {
                h2 = Math.min(nat2, min2 * 2);
            }
            else if (h + min2 <= height) {
                h2 = min2;
            }
        }
        this._description.opacity = h2 > 0 ? 255 : 0;
        h += h2;
        // Image
        let h0 = 0;
        if (nat0 > 0) {
            if (!vertical) {
                h0 = height;
            }
            else if (height - h > 30) {
                spacing = IMAGE_SPACING;
                h0 = height - h - spacing;
            }
        }
        if (this._image)
            this._image.opacity = h0 > 0 ? 255 : 0;
        if (vertical)
            h += h0;
        // Url
        const line3 = min3 - this._url.get_theme_node().get_vertical_padding();
        const h3 = Math.min(min3 + Math.max(Math.floor((height - h) / line3) * line3, 0), nat3);
        // Allocate
        this._image?.allocate(Clutter.ActorBox.new(0, 0, imageWidth, h0));
        let y = vertical ? h0 + spacing : spacing;
        this._title.allocate(Clutter.ActorBox.new(x, y, width, y + h1));
        y += h1;
        this._description.allocate(Clutter.ActorBox.new(x, y, width, y + h2));
        y += h2;
        // If image, title and description are hidden, show larger url
        if (y > SPACING) {
            this._url.opacity = 255;
            this._singleUrl.opacity = 0;
            this._url.allocate(Clutter.ActorBox.new(x, y, width, y + h3));
        }
        else {
            // Add extra top padding for same alignment as text item
            if (this._topPadding)
                y += SPACING;
            this._url.opacity = 0;
            this._singleUrl.opacity = 255;
            this._singleUrl.allocate(Clutter.ActorBox.new(x, y, width, height));
        }
    }
    destroy() {
        this._cancellable.cancel();
        super.destroy();
    }
};
LinkPreview = __decorate([
    registerClass({
        Properties: {
            'metadata': GObject.ParamSpec.jsobject('metadata', null, null, GObject.ParamFlags.READWRITE),
            'show-image': GObject.ParamSpec.boolean('show-image', null, null, GObject.ParamFlags.READWRITE, false),
            'background-size': enumParamSpec('background-size', GObject.ParamFlags.READWRITE, BackgroundSize, BackgroundSize.Contain),
            'orientation': enumParamSpec('orientation', GObject.ParamFlags.READWRITE, Clutter.Orientation, Clutter.Orientation.VERTICAL),
            'active': flagsParamSpec('active', GObject.ParamFlags.WRITABLE, ActiveState, ActiveState.None),
            'top-padding': GObject.ParamSpec.boolean('top-padding', null, null, GObject.ParamFlags.WRITABLE, false),
        },
    })
], LinkPreview);
export { LinkPreview };
let LinkItem = class LinkItem extends ClipboardItem {
    linkItemSettings;
    _linkPreview;
    _url;
    _cancellable = new Gio.Cancellable();
    constructor(ext, entry) {
        super(ext, entry, Icon.Link, _('Link'));
        this.linkItemSettings = this.ext.settings.get_child('link-item');
        this.add_style_class_name('link-item');
        this._linkPreview = new LinkPreview(ext, this.entry.content.trim());
        this._content.add_child(this._linkPreview);
        this._url = new St.Label({ style_class: 'link-url', text: this.entry.content.trim() });
        this._url.clutter_text.line_wrap = true;
        this._url.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
        this._content.add_child(this._url);
        // Bind properties
        this.linkItemSettings.connectObject('changed', this.updateLinkPreview.bind(this), this);
        this.ext.settings.connectObject('changed::show-header', this.updateLinkPreview.bind(this), this);
        this.bind_property('active', this._linkPreview, 'active', GObject.BindingFlags.DEFAULT);
        this.updateLinkPreview().catch(() => { });
    }
    search(query) {
        const metadata = { title: null, description: null, image: null, ...this.entry.metadata };
        const searchTexts = [this.entry.content];
        if (metadata.title)
            searchTexts.push(metadata.title);
        if (metadata.description)
            searchTexts.push(metadata.description);
        this.visible = query.matchesEntry(this.visible, this.entry, ...searchTexts);
    }
    async updateLinkPreview() {
        const patterns = this.linkItemSettings.get_strv('link-preview-exclusion-patterns');
        let regex = null;
        if (patterns.length > 0) {
            try {
                regex = new RegExp(patterns.join('|'));
            }
            catch {
                // Ignore
            }
        }
        const url = this.entry.content.trim();
        const showLinkPreview = this.linkItemSettings.get_boolean('show-link-preview');
        const showLinkPreviewImage = this.linkItemSettings.get_boolean('show-link-preview-image');
        const backgroundSize = this.linkItemSettings.get_enum('link-preview-image-background-size');
        const orientation = this.linkItemSettings.get_enum('link-preview-orientation');
        const showHeader = this.ext.settings.get_boolean('show-header');
        const show = showLinkPreview && !regex?.test(url);
        this._linkPreview.visible = show;
        this._linkPreview.showImage = showLinkPreviewImage;
        this._linkPreview.backgroundSize = backgroundSize;
        this._linkPreview.orientation = orientation;
        this._linkPreview.topPadding = !showHeader;
        this._url.visible = !show;
        if (this.entry.metadata) {
            const metadata = { title: null, description: null, image: null, ...this.entry.metadata };
            this._linkPreview.metadata ??= metadata;
        }
        else if (show) {
            const metadata = await tryGetMetadata(this.ext, url, this._cancellable);
            this.entry.metadata = metadata;
            this._linkPreview.metadata = metadata;
        }
    }
    destroy() {
        this.linkItemSettings.disconnectObject(this);
        this._cancellable.cancel();
        super.destroy();
    }
};
LinkItem = __decorate([
    registerClass()
], LinkItem);
export { LinkItem };
