// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
// SPDX-License-Identifier: LGPL-3.0-or-later

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import "../.."
import "../../Base"
import "../../Base/Buttons"
import "../../Dialogs"

HFlickableColumnPage {
    id: page

    property string userId
    readonly property QtObject account: ModelStore.get("accounts").find(userId)
    readonly property bool ready: account && account.profile_updated >= new Date(1)

    function takeFocus() {
        nameField.item.forceActiveFocus()
    }

    function applyChanges() {
        if (avatar.changed) {
            saveButton.avatarChangeRunning = true

            const path =
                Qt.resolvedUrl(avatar.sourceOverride).replace(/^file:/, "")

            py.callClientCoro(userId, "set_avatar_from_file", [path], () => {
                py.callClientCoro(userId, "update_own_profile", [], () => {
                    saveButton.avatarChangeRunning = false
                })

            }, (errType, [httpCode]) => {
                console.error("Avatar upload failed:", httpCode, errType)
                saveButton.avatarChangeRunning = false
            })
        }

        if (nameField.item.changed) {
            saveButton.nameChangeRunning = true
            const name                   = nameField.item.text

            py.callClientCoro(userId, "set_displayname", [name] , () => {
                py.callClientCoro(userId, "update_own_profile", [], () => {
                    saveButton.nameChangeRunning = false
                })
            })
        }

        if (aliasFieldItem.changed) {
            window.settings.Chat.Composer.Aliases[userId] =
                aliasFieldItem.text

            window.saveSettings()
        }

        if (ignoredUsersAreaItem.changed) {
            saveButton.ignoredUsersChangeRunning = true
            const users                          = ignoredUsers.userIds

            py.callClientCoro(userId, "set_ignored_users", users, () => {
                saveButton.ignoredUsersChangeRunning = false
            })
        }
    }

    function cancel() {
        if (
            ! nameField.item.changed &&
            ! aliasFieldItem.changed &&
            ! fileDialog.selectedFile &&
            ! fileDialog.file
        ) {
            pageLoader.showPrevious() || mainUI.mainPane.toggleFocus()
            return
        }

        nameField.item.reset()
        aliasFieldItem.reset()
        fileDialog.selectedFile = ""
        fileDialog.file         = ""
    }

    footer: AutoDirectionLayout {
        ApplyButton {
            id: saveButton

            property bool nameChangeRunning: false
            property bool avatarChangeRunning: false
            property bool ignoredUsersChangeRunning: false

            disableWhileLoading: false
            loading:
                nameChangeRunning ||
                avatarChangeRunning ||
                ignoredUsersChangeRunning

            enabled:
                avatar.changed ||
                nameField.item.changed ||
                (aliasFieldItem.changed && ! aliasFieldItem.error) ||
                (ignoredUsersAreaItem.changed && ! ignoredUsersAreaItem.error)

            onClicked: applyChanges()
        }

        CancelButton {
            enabled: ! saveButton.loading
            onClicked: cancel()
        }
    }

    onKeyboardAccept: if (saveButton.enabled) saveButton.clicked()
    onKeyboardCancel: cancel()

    HUserAvatar {
        id: avatar

        property bool changed: Boolean(sourceOverride)

        clientUserId: page.userId
        userId: page.userId
        displayName: nameField.item.text
        mxc: account ? account.avatar_url : ""
        toolTipMxc: ""
        sourceOverride: fileDialog.selectedFile || fileDialog.file

        Layout.alignment: Qt.AlignHCenter
        Layout.fillWidth: true
        // Layout.preferredWidth: 256 * theme.uiScale
        Layout.preferredHeight: width

        HoverHandler { id: overlayHover }

        Rectangle {
            anchors.fill: parent
            z: 10
            visible: opacity > 0
            opacity:
                ! fileDialog.dialog.visible &&
                (
                    (! avatar.mxc && ! avatar.changed) ||
                    avatar.hovered ||
                    ! ready ||
                    account.presence === "offline"
                ) ?
                1 :
                0

            color: utils.hsluv(
                0, 0, 0, (! avatar.mxc && overlayHover.hovered) ? 0.8 : 0.7,
            )

            Behavior on opacity { HNumberAnimation {} }
            Behavior on color { HColorAnimation {} }

            MouseArea {
                anchors.fill: parent
                enabled: ready && account.presence !== "offline"
                acceptedButtons: Qt.NoButton
                cursorShape:
                    overlayHover.hovered ?
                    Qt.PointingHandCursor : Qt.ArrowCursor
            }

            HLoader {
                anchors.centerIn: parent
                width: avatar.width / 3
                height: width

                source: "../../Base/HBusyIndicator.qml"
                active: ! ready
                opacity: active ? 1 : 0
                visible: opacity > 0

                Behavior on opacity { HNumberAnimation {} }
            }

            HColumnLayout {
                anchors.centerIn: parent
                spacing: currentSpacing
                width: parent.width
                opacity: ready && account.presence !== "offline" ? 1 : 0
                visible: opacity > 0

                Behavior on opacity { HNumberAnimation {} }

                HIcon {
                    svgName: "upload-avatar"
                    colorize: (! avatar.mxc && overlayHover.hovered) ?
                              theme.colors.accentText : theme.icons.colorize
                    dimension: avatar.width / 3

                    Layout.alignment: Qt.AlignCenter
                }

                Item { Layout.preferredHeight: theme.spacing }

                HLabel {
                    text: avatar.mxc ?
                          qsTr("Change profile picture") :
                          qsTr("Upload profile picture")

                    color: (! avatar.mxc && overlayHover.hovered) ?
                           theme.colors.accentText : theme.colors.brightText
                    Behavior on color { HColorAnimation {} }

                    font.pixelSize: Math.max(
                        theme.fontSize.big * avatar.width / 300,
                        theme.fontSize.small,
                    )
                    wrapMode: HLabel.WordWrap
                    horizontalAlignment: Qt.AlignHCenter

                    Layout.fillWidth: true
                }
            }
        }

        HFileDialogOpener {
            id: fileDialog
            enabled: ready
            fileType: HFileDialogOpener.FileType.Images
            dialog.title: qsTr("Select profile picture for %1")
                              .arg(account ? account.display_name : "")
        }
    }

    HLabeledItem {
        label.text: qsTr("User ID:")

        Layout.fillWidth: true

        HRowLayout {
            width: parent.width

            HTextArea {
                id: idArea
                textFormat: HSelectableLabel.RichText
                wrapMode: HLabel.Wrap
                readOnly: true
                radius: 0
                text: utils.coloredNameHtml("", userId, userId)

                Layout.fillWidth: true
                Layout.fillHeight: true
            }

            FieldCopyButton {
                textControl: idArea
            }
        }
    }

    HLabeledItem {
        id: nameField
        loading: ! ready
        label.text: qsTr("Display name:")

        Layout.fillWidth: true

        HTextField {
            width: parent.width
            enabled: ready && account.presence !== "offline"
            defaultText: ready ? account.display_name : ""
            maximumLength: 255

            // TODO: Qt 5.14+: use a Binding enabled when text not empty
            color: utils.nameColor(text)
        }
    }

    HLabeledItem {
        id: aliasField

        readonly property var aliases: window.settings.Chat.Composer.Aliases
        readonly property string currentAlias: aliases[userId] || ""

        readonly property bool hasWhiteSpace: /\s/.test(item.text)

        readonly property string alreadyTakenBy: {
            if (! item.text) return ""

            for (const [id, idAlias] of Object.entries(aliases))
                if (id !== userId && idAlias === item.text) return id

            return ""
        }

        label.text: qsTr("Composer alias:")

        errorLabel.text:
            hasWhiteSpace ? qsTr("Alias cannot include spaces") :
            alreadyTakenBy ? qsTr("Taken by %1").arg(alreadyTakenBy) :
            ""

        Layout.fillWidth: true

        HRowLayout {
            width: parent.width

            HTextField {
                id: aliasFieldItem
                error: aliasField.hasWhiteSpace || aliasField.alreadyTakenBy
                defaultText: aliasField.currentAlias
                placeholderText: qsTr("e.g. %1").arg((
                    nameField.item.text ||
                    (ready && account.display_name) ||
                    userId.substring(1)
                )[0])

                Layout.fillWidth: true
                Layout.fillHeight: true
            }

            FieldHelpButton {
                helpText: qsTr(
                    "From any chat, start a message with the specified " +
                    "alias, followed by a space, to type and send as " +
                    "this account.\n\n" +

                    "The account must be a member of the room and have " +
                    "permission to talk.\n\n"+

                    "To ignore the alias when typing, prepend it with a space."
                )
            }
        }
    }

    HLabeledItem {
        id: ignoredUsers

        readonly property var userIds:
            ! ignoredUsersAreaItem.text.trim() ?
            [] :
            ignoredUsersAreaItem.text.trim().split(/\s+/)

        readonly property var invalidUserIds: {
            const result = []

            for (const user of userIds)
                if (! /@.+:.+/.test(user))
                    result.push(user)

            return result
        }

        loading: ! ready
        label.text: qsTr("Ignored users:")
        errorLabel.text:
            invalidUserIds.length ?
            qsTr("Incomplete user ID: %1").arg(invalidUserIds.join(", ")) :
            ""

        Layout.fillWidth: true

        HRowLayout {
            width: parent.width

            HTextArea {
                id: ignoredUsersAreaItem
                error: ignoredUsers.invalidUserIds.length > 0
                focusItemOnTab: ignoredUsersHelpButton
                placeholderText: qsTr("@user1:example.org @user2:ex.org")
                defaultText:
                    ready ?
                    JSON.parse(account.ignored_users).sort().join(" ") :
                    ""

                Layout.fillWidth: true
                Layout.fillHeight: true
            }

            FieldHelpButton {
                id: ignoredUsersHelpButton
                helpText: qsTr(
                    "List of user IDs, separated by a space, from which you " +
                    "will not receive messages or room invites.\n\n" +

                    "Their display name, avatar and online status will also " +
                    "be hidden from room member lists.\n\n" +

                    "When removing an user from the ignore list, restarting " +
                    "%1 is needed to receive anything they might have sent " +
                    "while being ignored."
                ).arg(Qt.application.displayName)
            }
        }
    }
}
