// SPDX-License-Identifier: LGPL-3.0-or-later

import QtQuick 2.12
import "../../.."
import "../../../Base"

HTextArea {
    id: textArea


    property HListView eventList

    property string indent: "    "

    property string toSend: ""
    property bool textChangedSinceLostFocus: false
    property string writingUserId: chat.userId

    readonly property QtObject writingUserInfo:
        ModelStore.get("accounts").find(writingUserId)

    readonly property int cursorY:
        textArea.text.substring(0, cursorPosition).split("\n").length - 1

    readonly property int cursorX:
        cursorPosition - lines.slice(0, cursorY).join("").length - cursorY

    readonly property var lines: textArea.text.split("\n")
    readonly property string lineText: lines[cursorY] || ""

    readonly property string lineTextUntilCursor:
        lineText.substring(0, cursorX)

    // readonly property int deleteCharsOnBackspace:
    //     lineTextUntilCursor.match(/^ +$/) ?
    //     lineTextUntilCursor.match(/ {1,4}/g).slice(-1)[0].length :
    //     1

    readonly property var usableAliases: {
        const obj = {}

        // Get accounts that are members of this room with permission to talk
        for (const [id, alia] of Object.entries(window.settings.writeAliases)){
            const room = ModelStore.get(id, "rooms").find(chat.roomId)
            if (room &&
                    ! room.inviter_id && ! room.left && room.can_send_messages)
                obj[id] = alia
        }

        return obj
    }


    function setTyping(typing) {
        py.callClientCoro(
            writingUserId, "room_typing", [chat.roomId, typing, 5000],
        )
    }

    function clearReplyTo() {
        if (! chat.replyToEventId) return

        chat.replyToEventId     = ""
        chat.replyToUserId      = ""
        chat.replyToDisplayName = ""
    }

    function addNewLine() {
        let indents = 0
        const parts = lineText.split(indent)

        for (const [i, part] of parts.entries()) {
            if (i === parts.length - 1 || part) { break }
            indents += 1
        }

        const add = indent.repeat(indents)
        textArea.insertAtCursor("\n" + add)
    }

    function sendText() {
        if (! toSend) return

        const args = [chat.roomId, toSend, chat.replyToEventId]
        py.callClientCoro(writingUserId, "send_text", args)

        textArea.clear()
        clearReplyTo()
    }


    saveName: "composer"
    saveId: [chat.roomId, writingUserId]

    enabled: chat.roomInfo.can_send_messages
    disabledText: qsTr("You do not have permission to post in this room")
    placeholderText: qsTr("Type a message...")

    backgroundColor: "transparent"
    focusedBorderColor: "transparent"
    tabStopDistance: 4 * 4  // 4 spaces
    focus: true

    // TODO: make this more declarative
    onTextChanged: {
        if (utils.isEmptyObject(usableAliases)) {
            writingUserId = Qt.binding(() => chat.userId)
            toSend        = text
            setTyping(Boolean(text))
            textChangedSinceLostFocus = true
            return
        }

        let foundAlias = null

        for (const [user, writing_alias] of Object.entries(usableAliases)) {
            if (text.startsWith(writing_alias + " ")) {
                writingUserId = user
                foundAlias = new RegExp("^" + writing_alias + " ")
                break
            }
        }

        if (foundAlias) {
            toSend = text.replace(foundAlias, "")
            setTyping(Boolean(text))
            textChangedSinceLostFocus = true
            return
        }

        writingUserId = Qt.binding(() => chat.userId)
        toSend        = text

        const vals = Object.values(usableAliases)

        const longestAlias =
            vals.reduce((a, b) => a.length > b.length ? a: b)

        const textNotStartsWithAnyAlias =
            ! vals.some(a => a.startsWith(text))

        const textContainsCharNotInAnyAlias =
            vals.every(a => text.split("").some(c => ! a.includes(c)))

        // Only set typing when it's sure that the user will not use
        // an alias and has written something
        if (toSend &&
            (text.length > longestAlias.length ||
             textNotStartsWithAnyAlias ||
             textContainsCharNotInAnyAlias))
        {
            setTyping(Boolean(text))
            textChangedSinceLostFocus = true
        }
    }

    onEditingFinished: {  // when focus is lost
        if (text && textChangedSinceLostFocus) {
            setTyping(false)
            textChangedSinceLostFocus = false
        }
    }

    Keys.onEscapePressed: clearReplyTo()

    Keys.onReturnPressed: ev => {
        ev.accepted = true

        ev.modifiers & Qt.ShiftModifier ||
        ev.modifiers & Qt.ControlModifier ||
        ev.modifiers & Qt.AltModifier ?
        addNewLine() :
        sendText()
    }

    Keys.onEnterPressed: ev => Keys.returnPressed(ev)

    Keys.onTabPressed: ev => {
        ev.accepted = true
        textArea.insertAtCursor(indent)
    }

    Keys.onPressed: ev => {
        if (ev.matches(StandardKey.Copy) &&
            ! textArea.selectedText &&
            eventList &&
            (eventList.selectedCount || eventList.currentIndex !== -1))
        {
            ev.accepted = true
            eventList.copySelectedDelegates()
            return
        }

        // FIXME: buggy
        // if (ev.modifiers === Qt.NoModifier &&
        //     ev.key === Qt.Key_Backspace &&
        //     ! textArea.selectedText)
        // {
        //     ev.accepted = true
        //     textArea.remove(
        //         cursorPosition - deleteCharsOnBackspace,
        //         cursorPosition
        //     )
        // }
    }
}