// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts

import NdefEditor

ApplicationWindow {
    id: window

    enum TargetDetectedAction {
        NoAction,
        ReadMessage,
        WriteMessage
    }

    StackView {
        id: stack
        initialItem: mainView
        anchors.fill: parent
    }

    property int targetDetectedAction: MainWindow.NoAction

    Component {
        id: mainView

        ColumnLayout {
            ToolBar {
                Layout.fillWidth: true

                RowLayout {
                    anchors.fill: parent
                    Label {
                        text: qsTr("NDEF Editor")
                        elide: Label.ElideRight
                        horizontalAlignment: Qt.AlignHCenter
                        verticalAlignment: Qt.AlignVCenter
                        Layout.fillWidth: true
                    }
                }
            }

            Pane {
                id: writeTab
                Layout.fillWidth: true
                Layout.fillHeight: true

                Flickable {
                    anchors.fill: parent
                    contentHeight: contentItem.childrenRect.height

                    ColumnLayout {
                        width: parent.width

                        ItemDelegate {
                            icon.name: "file_download"
                            text: qsTr("Read Tag")
                            Layout.fillWidth: true

                            onClicked: window.readTag()
                        }

                        ItemDelegate {
                            icon.name: "file_upload"
                            text: qsTr("Write to Tag")
                            Layout.fillWidth: true

                            onClicked: window.writeTag()
                        }

                        ItemDelegate {
                            icon.name: "add"
                            text: qsTr("Add a Record")
                            Layout.fillWidth: true

                            onClicked: addRecordMenu.open()

                            Menu {
                                id: addRecordMenu
                                title: qsTr("Add record")

                                MenuItem {
                                    icon.name: "text_snippet"
                                    text: qsTr("Text record")
                                    onTriggered: stack.push(textRecordDialog)
                                }
                                MenuItem {
                                    icon.name: "link"
                                    text: qsTr("URI record")
                                    onTriggered: stack.push(uriRecordDialog)
                                }
                            }
                        }

                        Item {
                            implicitHeight: 20
                        }

                        Label {
                            text: qsTr(
                                "Use buttons above to read an NFC tag or add records manually.\n\n"
                                + "Once added, swipe to the right to access options for each record.")
                            wrapMode: Text.Wrap
                            visible: messages.count === 0
                            Layout.fillWidth: true
                        }

                        Repeater {
                            id: messages
                            model: messageModel

                            delegate: NdefRecordDelegate {
                                Layout.fillWidth: true

                                onDeleteClicked: messageModel.removeRow(index)

                                onClicked: {
                                    if (recordType === NdefMessageModel.TextRecord) {
                                        stack.push(textRecordDialog, {
                                            text: recordText,
                                            modelIndex: index
                                        })
                                    } else if (recordType === NdefMessageModel.UriRecord) {
                                        stack.push(uriRecordDialog, {
                                            uri: recordText,
                                            modelIndex: index
                                        })
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    NdefMessageModel {
        id: messageModel
    }

    NfcManager {
        id: nfcManager
        onTargetDetected: (target) => { window.handleTargetDetected(target) }
    }

    Connections {
        id: targetConnections
        target: null

        function onNdefMessageRead(message) {
            messageModel.message = message
        }

        function onRequestCompleted() {
            communicationOverlay.close()
            window.targetDetectedAction = MainWindow.NoAction
            releaseTarget()
        }

        function onError(code) {
            communicationOverlay.close()
            errorNotification.errorMessage = window.describeError(code)
            errorNotification.open()
            window.targetDetectedAction = MainWindow.NoAction
            releaseTarget()
        }

        function releaseTarget() {
            target?.destroy()
        }
    }

    function handleTargetDetected(target: NfcTarget) {
        targetConnections.releaseTarget()

        let ok = true

        if (targetDetectedAction === MainWindow.ReadMessage) {
            targetConnections.target = target
            communicationOverlay.message = qsTr("Target detected. Reading messages...")
            errorNotification.errorMessage = qsTr("NDEF read error")
            ok = target.readNdefMessages()
        } else if (targetDetectedAction === MainWindow.WriteMessage) {
            targetConnections.target = target
            communicationOverlay.message = qsTr("Target detected. Writing the message...")
            errorNotification.errorMessage = qsTr("NDEF write error")
            ok = target.writeNdefMessage(messageModel.message)
        } else {
            target.destroy()
            return
        }

        if (!ok) {
            communicationOverlay.close()
            errorNotification.open()
            targetConnections.releaseTarget()
        }
    }

    function readTag() {
        messageModel.clearMessage()
        window.targetDetectedAction = MainWindow.ReadMessage
        nfcManager.startTargetDetection()
        communicationOverlay.title = qsTr("Read Tag")
        communicationOverlay.message = qsTr("Approach an NFC tag.")
        communicationOverlay.open()
    }

    function writeTag() {
        window.targetDetectedAction = MainWindow.WriteMessage
        nfcManager.startTargetDetection()
        communicationOverlay.title = qsTr("Write to Tag")
        communicationOverlay.message = qsTr("Approach an NFC tag.")
        communicationOverlay.open()
    }

    function describeError(error) {
        switch (error) {
        case 2: return qsTr("Usupported feature")
        case 3: return qsTr("Target out of range")
        case 4: return qsTr("No response")
        case 5: return qsTr("Checksum mismatch")
        case 6: return qsTr("Invalid parameters")
        case 7: return qsTr("Connection error")
        case 8: return qsTr("NDEF read error")
        case 9: return qsTr("NDEF write error")
        case 10: return qsTr("Command error")
        case 11: return qsTr("Timeout")
        }

        return qsTr("Unknown error")
    }

    Dialog {
        id: communicationOverlay

        property alias message: messageLabel.text

        anchors.centerIn: Overlay.overlay

        modal: true
        standardButtons: Dialog.Cancel

        ColumnLayout {
            Label {
                id: messageLabel
            }

            BusyIndicator {
                Layout.fillWidth: true
            }
        }

        onClosed: nfcManager.stopTargetDetection()
    }

    MessageDialog {
        property alias errorMessage: errorNotification.text

        id: errorNotification

        buttons: MessageDialog.Close
        title: qsTr("Error")

        onButtonClicked: errorNotification.close()
    }

    Component {
        id: uriRecordDialog

        ColumnLayout {
            property alias uri: uriEditor.text
            property int modelIndex: -1

            ToolBar {
                Layout.fillWidth: true

                RowLayout {
                    anchors.fill: parent
                    ToolButton {
                        icon.name: "arrow_back"
                        onClicked: stack.pop()
                    }
                    Label {
                        text: qsTr("URI Record")
                        elide: Label.ElideRight
                        horizontalAlignment: Qt.AlignHCenter
                        verticalAlignment: Qt.AlignVCenter
                        Layout.fillWidth: true
                    }
                    ToolButton {
                        text: qsTr("Save")
                        onClicked: {
                            if (modelIndex < 0) {
                                messageModel.addUriRecord(uri)
                            } else {
                                messageModel.setTextData(modelIndex, uri)
                            }
                            stack.pop()
                        }
                    }
                }
            }

            Pane {
                Layout.fillWidth: true
                Layout.fillHeight: true

                ColumnLayout {
                    anchors.fill: parent

                    TextField {
                        id: uriEditor
                        Layout.fillWidth: true
                        placeholderText: qsTr("https://qt.io")
                        inputMethodHints: Qt.ImhUrlCharactersOnly
                    }
                    Item {
                        Layout.fillHeight: true
                    }
                }
            }
        }
    }

    Component {
        id: textRecordDialog

        ColumnLayout {
            property alias text: textEditor.text
            property int modelIndex: -1

            ToolBar {
                Layout.fillWidth: true

                RowLayout {
                    anchors.fill: parent
                    ToolButton {
                        icon.name: "arrow_back"
                        onClicked: stack.pop()
                    }
                    Label {
                        text: qsTr("Text Record")
                        elide: Label.ElideRight
                        horizontalAlignment: Qt.AlignHCenter
                        verticalAlignment: Qt.AlignVCenter
                        Layout.fillWidth: true
                    }
                    ToolButton {
                        text: qsTr("Save")
                        onClicked: {
                            if (modelIndex < 0) {
                                messageModel.addTextRecord(textEditor.text)
                            } else {
                                messageModel.setTextData(modelIndex, textEditor.text)
                            }
                            stack.pop()
                        }
                    }
                }
            }

            Pane {
                Layout.fillWidth: true
                Layout.fillHeight: true

                ScrollView {
                    anchors.fill: parent

                    TextArea {
                        id: textEditor
                        placeholderText: qsTr("Enter some text...")
                        Layout.fillWidth: true
                    }
                }
            }
        }
    }
}
