// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect
//
// SPDX-License-Identifier: GPL-2.0-or-later

import GObject from 'gi://GObject';

import * as Components from '../components/index.js';
import Plugin from '../plugin.js';


export const Metadata = {
    label: _('Clipboard'),
    description: _('Share the clipboard content'),
    id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Clipboard',
    incomingCapabilities: [
        'kdeconnect.clipboard',
        'kdeconnect.clipboard.connect',
    ],
    outgoingCapabilities: [
        'kdeconnect.clipboard',
        'kdeconnect.clipboard.connect',
    ],
    actions: {
        clipboardPush: {
            label: _('Clipboard Push'),
            icon_name: 'edit-paste-symbolic',

            parameter_type: null,
            incoming: [],
            outgoing: ['kdeconnect.clipboard'],
        },
        clipboardPull: {
            label: _('Clipboard Pull'),
            icon_name: 'edit-copy-symbolic',

            parameter_type: null,
            incoming: ['kdeconnect.clipboard'],
            outgoing: [],
        },
    },
};


/**
 * Clipboard Plugin
 * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/clipboard
 */
const ClipboardPlugin = GObject.registerClass({
    GTypeName: 'GSConnectClipboardPlugin',
}, class ClipboardPlugin extends Plugin {

    _init(device) {
        super._init(device, 'clipboard');

        this._clipboard = Components.acquire('clipboard');

        // Watch local clipboard for changes
        this._textChangedId = this._clipboard.connect(
            'notify::text',
            this._onLocalClipboardChanged.bind(this)
        );

        // Buffer content to allow selective sync
        this._localBuffer = this._clipboard.text;
        this._localTimestamp = 0;
        this._remoteBuffer = null;
    }

    connected() {
        super.connected();

        // TODO: if we're not auto-syncing local->remote, but we are doing the
        //       reverse, it's possible older remote content will end up
        //       overwriting newer local content.
        if (!this.settings.get_boolean('send-content'))
            return;

        if (this._localBuffer === null && this._localTimestamp === 0)
            return;

        this.device.sendPacket({
            type: 'kdeconnect.clipboard.connect',
            body: {
                content: this._localBuffer,
                timestamp: this._localTimestamp,
            },
        });
    }

    handlePacket(packet) {
        if (!packet.body.hasOwnProperty('content'))
            return;

        switch (packet.type) {
            case 'kdeconnect.clipboard':
                this._handleContent(packet);
                break;

            case 'kdeconnect.clipboard.connect':
                this._handleConnectContent(packet);
                break;
        }
    }

    _handleContent(packet) {
        this._onRemoteClipboardChanged(packet.body.content);
    }

    _handleConnectContent(packet) {
        if (packet.body.hasOwnProperty('timestamp') &&
            packet.body.timestamp > this._localTimestamp)
            this._onRemoteClipboardChanged(packet.body.content);
    }

    /*
     * Store the local clipboard content and forward it if enabled
     */
    _onLocalClipboardChanged(clipboard, pspec) {
        this._localBuffer = clipboard.text;
        this._localTimestamp = Date.now();

        if (this.settings.get_boolean('send-content'))
            this.clipboardPush();
    }

    /*
     * Store the remote clipboard content and apply it if enabled
     */
    _onRemoteClipboardChanged(text) {
        this._remoteBuffer = text;

        if (this.settings.get_boolean('receive-content'))
            this.clipboardPull();
    }

    /**
     * Copy to the remote clipboard; called by _onLocalClipboardChanged()
     */
    clipboardPush() {
        // Don't sync if the clipboard is empty or not text
        if (this._localTimestamp === 0)
            return;

        if (this._remoteBuffer !== this._localBuffer) {
            this._remoteBuffer = this._localBuffer;

            // If the buffer is %null, the clipboard contains non-text content,
            // so we neither clear the remote clipboard nor pass the content
            if (this._localBuffer !== null) {
                this.device.sendPacket({
                    type: 'kdeconnect.clipboard',
                    body: {
                        content: this._localBuffer,
                    },
                });
            }
        }
    }

    /**
     * Copy from the remote clipboard; called by _onRemoteClipboardChanged()
     */
    clipboardPull() {
        if (this._localBuffer !== this._remoteBuffer) {
            this._localBuffer = this._remoteBuffer;
            this._localTimestamp = Date.now();

            this._clipboard.text = this._remoteBuffer;
        }
    }

    destroy() {
        if (this._clipboard && this._textChangedId) {
            this._clipboard.disconnect(this._textChangedId);
            this._clipboard = Components.release('clipboard');
        }

        super.destroy();
    }
});

export default ClipboardPlugin;
