// Printers, and one queue across all of them.
//
// The list answers "which printers exist"; the queue answers "where is my
// document", which is the question that actually brings someone here. They are
// separate cards because they are separate questions -- a job that has not come
// out is not necessarily a problem with the printer it was sent to.
//
// Driverless only. A printer old enough to need a PPD is named as such rather
// than offered and then failing at the moment it is added.

import Quickshell
import QtQuick
import qs.config
import qs.services

SettingsPage {
    id: root

    objectName: "printers"
    title: "Printers"
    lede: "Printers this machine can use, and what they are waiting on."

    property string expandedPrinter: ""
    property string confirmingRemoval: ""
    property bool addingByAddress: false
    property string manualUri: ""
    property string manualName: ""

    readonly property bool manualReady: /^(ipp|ipps|socket):\/\/\S+$/.test(root.manualUri)
        && root.manualName.trim() !== ""

    Component.onCompleted: Printers.refresh()

    TextRow {
        visible: Printers.lastError !== ""
        label: "Printing needs attention"
        detail: Printers.lastError
        value: ""
        divider: false
    }

    // ── Which printers exist ─────────────────────────────────────────────────

    SettingsCard {
        visible: Printers.anyPrinters
        title: "Printers"
        subtitle: "Open one to change what it does by default."

        Repeater {
            model: Printers.printers

            delegate: Column {
                id: printerBlock

                required property var modelData
                required property int index

                readonly property string name: String(printerBlock.modelData.name ?? "")
                readonly property bool open: root.expandedPrinter === printerBlock.name
                readonly property bool paused: String(printerBlock.modelData.state ?? "") === "stopped"

                width: parent.width

                SettingRow {
                    width: printerBlock.width
                    icon: printerBlock.paused ? "\u{F0026}" : "\u{F042A}"
                    label: String(printerBlock.modelData.description ?? printerBlock.name)
                        + (printerBlock.modelData.isDefault ? "  ·  Default" : "")
                    detail: Printers.stateSummary(printerBlock.modelData)
                        + " · " + String(printerBlock.modelData.uri ?? "")
                    value: Printers.jobsFor(printerBlock.name) + " job"
                        + (Printers.jobsFor(printerBlock.name) === 1 ? "" : "s")
                    activatable: !Printers.busy
                    divider: !printerBlock.open
                        && printerBlock.index < Printers.printers.length - 1
                    onActivated: {
                        root.confirmingRemoval = "";
                        root.expandedPrinter = printerBlock.open ? "" : printerBlock.name;
                    }
                }

                Column {
                    width: printerBlock.width
                    visible: printerBlock.open

                    TextRow {
                        width: printerBlock.width
                        label: "Model"
                        detail: "Reported by the printer itself"
                        value: String(printerBlock.modelData.makeAndModel ?? "Unknown")
                    }

                    ActionRow {
                        width: printerBlock.width
                        visible: !printerBlock.modelData.isDefault
                        label: "Use by default"
                        detail: "Applications print here unless they are told otherwise"
                        action: "Make default"
                        enabled: !Printers.busy
                        onTriggered: Printers.setDefault(printerBlock.name)
                    }

                    ActionRow {
                        width: printerBlock.width
                        label: printerBlock.paused ? "Resume printing" : "Pause printing"
                        detail: printerBlock.paused
                            ? "Queued jobs start again"
                            : "Jobs keep queuing, but nothing is sent until it resumes"
                        action: printerBlock.paused ? "Resume" : "Pause"
                        enabled: !Printers.busy
                        onTriggered: printerBlock.paused
                            ? Printers.resume(printerBlock.name)
                            : Printers.pause(printerBlock.name)
                    }

                    ActionRow {
                        width: printerBlock.width
                        label: "Print a test page"
                        detail: "Confirms the printer answers and puts ink on paper"
                        action: "Print"
                        enabled: !Printers.busy && !printerBlock.paused
                        onTriggered: Printers.testPage(printerBlock.name)
                    }

                    SettingRow {
                        width: printerBlock.width
                        label: "Remove this printer"
                        detail: root.confirmingRemoval === printerBlock.name
                            ? "Anything still queued for it is cancelled."
                            : "It can be added again later"
                        controlWidth: 200
                        divider: printerBlock.index < Printers.printers.length - 1

                        Row {
                            anchors.right: parent.right
                            anchors.verticalCenter: parent.verticalCenter
                            spacing: 8

                            SettingsButton {
                                text: root.confirmingRemoval === printerBlock.name ? "Keep" : "Remove…"
                                enabled: !Printers.busy
                                onClicked: root.confirmingRemoval =
                                    root.confirmingRemoval === printerBlock.name ? "" : printerBlock.name
                            }

                            SettingsButton {
                                visible: root.confirmingRemoval === printerBlock.name
                                text: "Remove"
                                tone: "danger"
                                enabled: !Printers.busy
                                onClicked: {
                                    root.confirmingRemoval = "";
                                    root.expandedPrinter = "";
                                    Printers.remove(printerBlock.name);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // ── Where my document is ─────────────────────────────────────────────────

    SettingsCard {
        visible: Printers.anyPrinters
        title: "Print queue"
        subtitle: Printers.jobs.length === 0
            ? "Nothing is waiting."
            : "Everything waiting, across every printer."

        Repeater {
            model: Printers.jobs

            delegate: ActionRow {
                id: jobRow

                required property var modelData
                required property int index

                width: parent.width
                label: String(jobRow.modelData.name ?? "Untitled")
                detail: String(jobRow.modelData.printer ?? "") + " · "
                    + String(jobRow.modelData.state ?? "")
                    + (Number(jobRow.modelData.pages ?? 0) > 0
                        ? " · " + jobRow.modelData.pages + " pages" : "")
                action: "Cancel"
                enabled: !Printers.busy
                divider: jobRow.index < Printers.jobs.length - 1
                onTriggered: Printers.cancel(Number(jobRow.modelData.id))
            }
        }

        TextRow {
            visible: Printers.jobs.length === 0
            label: "Queue is empty"
            detail: "Jobs appear here while they wait, and can be cancelled from here"
            value: ""
            divider: false
        }
    }

    // ── Nothing set up yet ───────────────────────────────────────────────────

    SettingsCard {
        visible: Printers.scanned && !Printers.anyPrinters
        title: "No printers yet"
        subtitle: "Printers that announce themselves on your network appear here on their own."

        ActionRow {
            label: "Search the network"
            detail: Printers.searching
                ? "Listening for printers that announce themselves…"
                : (Printers.searched
                    ? Printers.addable.length + " found"
                    : "Looks for printers over mDNS, the same way phones and laptops find them")
            action: Printers.searching ? "Searching…" : "Search"
            enabled: !Printers.searching
            divider: false
            onTriggered: Printers.search()
        }
    }

    // ── Adding ───────────────────────────────────────────────────────────────

    SettingsCard {
        title: "Add a printer"
        subtitle: "Driverless printers only. One that needs a manufacturer driver has to be set up with the system printer tool."

        ActionRow {
            visible: Printers.anyPrinters
            label: "Search the network"
            detail: Printers.searching
                ? "Listening for printers that announce themselves…"
                : (Printers.searched
                    ? Printers.addable.length + " printer"
                      + (Printers.addable.length === 1 ? "" : "s") + " found that are not set up here"
                    : "Looks for printers over mDNS")
            action: Printers.searching ? "Searching…" : "Search"
            enabled: !Printers.searching
            onTriggered: Printers.search()
        }

        Repeater {
            model: Printers.addable

            delegate: ActionRow {
                id: foundRow

                required property var modelData

                width: parent.width
                label: String(foundRow.modelData.name ?? "")
                detail: foundRow.modelData.driverless === true
                    ? String(foundRow.modelData.uri ?? "") + " · driverless"
                    : String(foundRow.modelData.uri ?? "") + " · needs a manufacturer driver"
                action: foundRow.modelData.driverless === true ? "Add" : "Not supported"
                enabled: !Printers.busy && foundRow.modelData.driverless === true
                onTriggered: Printers.add(String(foundRow.modelData.uri ?? ""),
                                          Printers.suggestedName(String(foundRow.modelData.name ?? "")))
            }
        }

        TextRow {
            visible: Printers.searched && Printers.addable.length === 0 && !Printers.searching
            label: "Nothing found"
            detail: "No printer announced itself. It may be asleep, on another network, or may not support network discovery."
            value: ""
        }

        ActionRow {
            label: "Add by address"
            detail: "For a printer that does not announce itself"
            action: root.addingByAddress ? "Cancel" : "Enter…"
            enabled: !Printers.busy
            divider: root.addingByAddress
            onTriggered: {
                root.addingByAddress = !root.addingByAddress;
                root.manualUri = "";
                root.manualName = "";
            }
        }

        Column {
            width: parent.width
            visible: root.addingByAddress

            TextFieldRow {
                width: parent.width
                label: "Address"
                detail: "ipp://, ipps://, or socket:// followed by the printer's host"
                placeholder: "ipp://printer.local/ipp/print"
                text: root.manualUri
                onAccepted: value => root.manualUri = value
            }

            TextFieldRow {
                width: parent.width
                label: "Name"
                detail: "What this printer is called on this machine"
                placeholder: "office-printer"
                text: root.manualName
                onAccepted: value => root.manualName = value
            }

            ActionRow {
                width: parent.width
                label: "Add this printer"
                detail: "The printer is asked what it can do; if it cannot answer, it is not added"
                action: "Add"
                enabled: root.manualReady && !Printers.busy
                divider: false
                onTriggered: {
                    Printers.add(root.manualUri, Printers.suggestedName(root.manualName));
                    root.addingByAddress = false;
                }
            }
        }
    }

    // ── The service underneath ───────────────────────────────────────────────

    SettingsCard {
        title: "Printing service"
        subtitle: "What has to be running for any of this to work."

        TextRow {
            label: "CUPS"
            detail: Printers.service?.running === true
                ? "Running, so a printer added here works immediately"
                : "Not running, so nothing can print"
            value: Printers.service?.running === true ? "Running" : "Stopped"
        }

        TextRow {
            label: "Starts at boot"
            detail: Printers.service?.startsAtBoot === true
                ? "Started with the system"
                : "Started on demand, when something prints. This is a normal configuration."
            value: Printers.service?.startsAtBoot === true ? "Yes" : "On demand"
        }

        TextRow {
            label: "Network discovery"
            detail: Printers.service?.discoveryAvailable === true
                ? "Avahi is running, which is what finds printers that announce themselves"
                : "Avahi is not running, so network printers cannot be discovered"
            value: Printers.service?.discoveryAvailable === true ? "Available" : "Unavailable"
            divider: false
        }
    }
}
