// SSH keys, and what this machine can reach with them.
//
// Read-heavy on purpose. The genuinely useful things a person wants from a page
// like this are "which key is this", "is the agent holding it", "copy the public
// half", and "forget a host whose key changed" -- and all four are safe. What is
// not here is generating a key, because a passphrase cannot be collected and
// handed to ssh-keygen without putting it somewhere it should not be, and a
// page offering to make an unencrypted key instead would be a downgrade
// disguised as a feature.

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

SettingsPage {
    id: root

    objectName: "ssh-keys"
    title: "SSH Keys"
    lede: "The keys this machine signs in with, and the hosts it has met."

    property string confirmingForget: ""

    Component.onCompleted: if (!SshKeys.scanned) SshKeys.refresh()

    TextRow {
        visible: SshKeys.lastError !== ""
        label: "That did not work"
        detail: SshKeys.lastError
        value: ""
        divider: false
    }

    TextRow {
        visible: SshKeys.scanned && !SshKeys.available
        label: "No SSH directory"
        detail: "Nothing has created ~/.ssh on this machine yet."
        value: ""
        divider: false
    }

    // ── Keys readable by other people ───────────────────────────────────────

    SettingsCard {
        visible: SshKeys.overexposed.length > 0
        title: SshKeys.overexposed.length === 1
            ? "A private key is readable by other accounts"
            : "Private keys are readable by other accounts"
        subtitle: "ssh refuses to use a key with these permissions, so it will never be offered."

        Repeater {
            model: SshKeys.overexposed

            delegate: TextRow {
                required property var modelData
                width: parent.width
                label: String(modelData.name ?? "")
                detail: "Mode " + String(modelData.mode ?? "") + " · should be 600"
                value: ""
            }
        }
    }

    // ── The agent ───────────────────────────────────────────────────────────

    SettingsCard {
        title: "Agent"
        subtitle: SshKeys.agent?.available === true
            ? (SshKeys.agent?.kind === "gnome-keyring"
                ? "The login keyring is holding your keys, and offers every key it finds in ~/.ssh."
                : "An SSH agent is holding your keys for this session.")
            : String(SshKeys.agent?.detail ?? "No SSH agent is running.")

        TextRow {
            label: "Holding"
            detail: SshKeys.agent?.available === true
                ? String(SshKeys.agent?.socket ?? "")
                : "Keys will be asked for on every connection"
            value: SshKeys.loadedCount + " key" + (SshKeys.loadedCount === 1 ? "" : "s")
            divider: SshKeys.agent?.kind === "gnome-keyring"
        }

        // Said plainly because it is measurable and surprising: ssh-add -d
        // reports success against this agent and the key is still offered a
        // moment later, because it is read back off disk.
        TextRow {
            visible: SshKeys.agent?.kind === "gnome-keyring"
            label: "Removing a key from this agent does not stick"
            detail: "It lists every key in ~/.ssh, so one removed comes straight back. Move the file out of ~/.ssh to stop it being offered."
            value: ""
            divider: false
        }
    }

    // ── Keys ────────────────────────────────────────────────────────────────

    SettingsCard {
        title: SshKeys.keys.length === 1 ? "Your key" : "Your keys"
        subtitle: SshKeys.keys.length === 0
            ? "No keys in " + SshKeys.directory
            : "Public halves are safe to share; the private half never leaves this machine."

        Repeater {
            model: SshKeys.keys

            delegate: SettingRow {
                id: keyRow

                required property var modelData
                required property int index

                label: String(keyRow.modelData.name ?? "")
                detail: String(keyRow.modelData.type ?? "") + " · "
                    + String(keyRow.modelData.fingerprint ?? "")
                    + (String(keyRow.modelData.comment ?? "") !== ""
                        ? " · " + keyRow.modelData.comment : "")
                    + (keyRow.modelData.encrypted === true
                        ? " · passphrase protected"
                        : (keyRow.modelData.encrypted === false ? " · no passphrase" : ""))
                divider: keyRow.index < SshKeys.keys.length - 1
                controlWidth: 220

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

                    Text {
                        anchors.verticalCenter: parent.verticalCenter
                        visible: keyRow.modelData.loaded === true
                        text: "In the agent"
                        color: Theme.fgDim
                        font.family: Theme.fontFamily
                        font.pixelSize: Theme.fontSizeSmall
                    }

                    SettingsButton {
                        anchors.verticalCenter: parent.verticalCenter
                        visible: keyRow.modelData.loaded !== true
                            && SshKeys.agent?.available === true
                        text: "Add to agent"
                        enabled: !SshKeys.busy
                        onClicked: SshKeys.addToAgent(String(keyRow.modelData.path))
                    }

                    SettingsButton {
                        anchors.verticalCenter: parent.verticalCenter
                        text: "Copy public key"
                        onClicked: SshKeys.copyPublicKey(String(keyRow.modelData.publicPath))
                    }
                }
            }
        }
    }

    // ── Known hosts ─────────────────────────────────────────────────────────

    SettingsCard {
        visible: SshKeys.hosts.length > 0
        title: "Known hosts"
        subtitle: "Machines this one has connected to before. Forgetting one means being asked to trust it again."

        Repeater {
            model: SshKeys.hosts

            delegate: SettingRow {
                id: hostRow

                required property var modelData
                required property int index

                readonly property bool confirming:
                    root.confirmingForget === String(hostRow.modelData.host ?? "")

                label: hostRow.modelData.hashed === true
                    ? hostRow.modelData.count + " hashed entries"
                    : String(hostRow.modelData.host ?? "")
                detail: hostRow.modelData.hashed === true
                    ? "Hashed on purpose, so the names cannot be read from the file"
                    : (hostRow.confirming
                        ? "You will be asked to trust this host the next time you connect."
                        : (hostRow.modelData.types ?? []).join(", "))
                divider: hostRow.index < SshKeys.hosts.length - 1
                controlWidth: 190

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

                    SettingsButton {
                        anchors.verticalCenter: parent.verticalCenter
                        visible: hostRow.confirming
                        text: "Forget it"
                        tone: "danger"
                        enabled: !SshKeys.busy
                        onClicked: {
                            root.confirmingForget = "";
                            SshKeys.forgetHost(String(hostRow.modelData.host));
                        }
                    }

                    SettingsButton {
                        anchors.verticalCenter: parent.verticalCenter
                        visible: hostRow.modelData.hashed !== true
                        text: hostRow.confirming ? "Keep" : "Forget…"
                        enabled: !SshKeys.busy
                        onClicked: root.confirmingForget = hostRow.confirming
                            ? "" : String(hostRow.modelData.host)
                    }
                }
            }
        }
    }
}
