pragma ComponentBehavior: Bound

import ".."
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Caelestia.Config
import qs.components
import qs.components.controls
import qs.components.effects
import qs.services

ColumnLayout {
    id: root

    required property Session session
    property bool showHeader: true
    property int pendingSwitchIndex: -1

    spacing: Tokens.spacing.medium

    Connections {
        function onConnectedChanged() {
            if (!VPN.connected && root.pendingSwitchIndex >= 0) {
                const targetIndex = root.pendingSwitchIndex;
                root.pendingSwitchIndex = -1;

                const providers = [];
                for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                    const p = GlobalConfig.utilities.vpn.provider[i];
                    if (typeof p === "object") {
                        const newProvider = {
                            name: p.name,
                            displayName: p.displayName,
                            interface: p.interface,
                            enabled: (i === targetIndex)
                        };
                        if (p.connectCmd && p.connectCmd.length > 0) {
                            newProvider.connectCmd = p.connectCmd;
                        }
                        if (p.disconnectCmd && p.disconnectCmd.length > 0) {
                            newProvider.disconnectCmd = p.disconnectCmd;
                        }
                        providers.push(newProvider);
                    } else {
                        providers.push(p);
                    }
                }
                GlobalConfig.utilities.vpn.provider = providers;

                Qt.callLater(function () {
                    VPN.toggle();
                });
            }
        }

        target: VPN
    }

    TextButton {
        Layout.fillWidth: true
        text: qsTr("+ Add VPN Provider")
        inactiveColour: Colours.palette.m3primaryContainer
        inactiveOnColour: Colours.palette.m3onPrimaryContainer

        onClicked: {
            vpnDialog.showProviderSelection();
        }
    }

    ListView {
        id: listView

        Layout.fillWidth: true
        Layout.preferredHeight: contentHeight

        interactive: false
        spacing: Tokens.spacing.medium

        model: ScriptModel {
            values: GlobalConfig.utilities.vpn.provider.map((provider, index) => {
                const isObject = typeof provider === "object";
                const name = isObject ? (provider.name || "custom") : String(provider);
                const displayName = isObject ? (provider.displayName || name) : name;
                const iface = isObject ? (provider.interface || "") : "";
                const enabled = isObject ? (provider.enabled === true) : false;

                return {
                    index: index,
                    name: name,
                    displayName: displayName,
                    interface: iface,
                    provider: provider,
                    enabled: enabled
                };
            })
        }

        delegate: Component {
            StyledRect {
                required property var modelData
                required property int index

                width: ListView.view ? ListView.view.width : undefined
                implicitHeight: rowLayout.implicitHeight + Tokens.padding.medium * 2

                color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (root.session && root.session.vpn && root.session.vpn.active === modelData) ? Colours.tPalette.m3surfaceContainer.a : 0)
                radius: Tokens.rounding.large

                StateLayer {
                    onClicked: {
                        if (root.session && root.session.vpn) {
                            root.session.vpn.active = modelData;
                        }
                    }
                }

                RowLayout {
                    id: rowLayout

                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.verticalCenter: parent.verticalCenter
                    anchors.margins: Tokens.padding.medium

                    spacing: Tokens.spacing.medium

                    StyledRect {
                        implicitWidth: implicitHeight
                        implicitHeight: icon.implicitHeight + Tokens.padding.medium * 2

                        radius: Tokens.rounding.large
                        color: modelData.enabled && VPN.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh

                        MaterialIcon {
                            id: icon

                            anchors.centerIn: parent
                            text: modelData.enabled && VPN.connected ? "vpn_key" : "vpn_key_off"
                            fontStyle: Tokens.font.icon.large
                            fill: modelData.enabled && VPN.connected ? 1 : 0
                            color: modelData.enabled && VPN.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
                        }
                    }

                    ColumnLayout {
                        Layout.fillWidth: true

                        spacing: 0

                        StyledText {
                            Layout.fillWidth: true
                            elide: Text.ElideRight
                            maximumLineCount: 1

                            text: modelData.displayName || qsTr("Unknown")
                        }

                        RowLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.medium

                            StyledText {
                                Layout.fillWidth: true
                                text: {
                                    if (!modelData.enabled)
                                        return qsTr("Disabled");

                                    if (VPN.connecting)
                                        return qsTr("Connecting...");

                                    switch (VPN.status.state) {
                                    case "connected":
                                        return qsTr("Connected");
                                    case "disconnected":
                                        return qsTr("Enabled");
                                    case "connecting":
                                        return qsTr("Connecting...");
                                    case "needs-auth":
                                        return qsTr("Auth required");
                                    case "error":
                                        return qsTr("Error");
                                    default:
                                        return qsTr("Enabled");
                                    }
                                }
                                color: {
                                    if (!modelData.enabled)
                                        return Colours.palette.m3outline;
                                    if (VPN.status.state === "connected")
                                        return Colours.palette.m3primary;
                                    if (VPN.status.state === "error")
                                        return Colours.palette.m3error;
                                    if (VPN.status.state === "needs-auth")
                                        return Colours.palette.m3tertiary;
                                    return Colours.palette.m3onSurface;
                                }
                                font: Tokens.font.body.builders.small.weight(modelData.enabled && VPN.connected ? Font.Medium : Font.Normal).build()
                                elide: Text.ElideRight
                            }
                        }
                    }

                    StyledRect {
                        implicitWidth: implicitHeight
                        implicitHeight: connectIcon.implicitHeight + Tokens.padding.large

                        radius: Tokens.rounding.full
                        color: Qt.alpha(Colours.palette.m3primaryContainer, VPN.connected && modelData.enabled ? 1 : 0)

                        StateLayer {
                            onClicked: {
                                const clickedIndex = modelData.index;

                                if (modelData.enabled) {
                                    VPN.toggle();
                                } else {
                                    if (VPN.connected) {
                                        root.pendingSwitchIndex = clickedIndex;
                                        VPN.toggle();
                                    } else {
                                        const providers = [];
                                        for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                                            const p = GlobalConfig.utilities.vpn.provider[i];
                                            if (typeof p === "object") {
                                                const newProvider = {
                                                    name: p.name,
                                                    displayName: p.displayName,
                                                    interface: p.interface,
                                                    enabled: (i === clickedIndex)
                                                };
                                                if (p.connectCmd && p.connectCmd.length > 0) {
                                                    newProvider.connectCmd = p.connectCmd;
                                                }
                                                if (p.disconnectCmd && p.disconnectCmd.length > 0) {
                                                    newProvider.disconnectCmd = p.disconnectCmd;
                                                }
                                                providers.push(newProvider);
                                            } else {
                                                providers.push(p);
                                            }
                                        }
                                        GlobalConfig.utilities.vpn.provider = providers;

                                        Qt.callLater(function () {
                                            VPN.toggle();
                                        });
                                    }
                                }
                            }

                            enabled: !VPN.connecting
                        }

                        MaterialIcon {
                            id: connectIcon

                            anchors.centerIn: parent
                            text: VPN.connected && modelData.enabled ? "link_off" : "link"
                            color: VPN.connected && modelData.enabled ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
                        }
                    }

                    StyledRect {
                        implicitWidth: implicitHeight
                        implicitHeight: deleteIcon.implicitHeight + Tokens.padding.large

                        radius: Tokens.rounding.full
                        color: "transparent"

                        StateLayer {
                            onClicked: {
                                const providers = [];
                                for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                                    if (i !== modelData.index) {
                                        const p = GlobalConfig.utilities.vpn.provider[i];
                                        const reconstructed = {
                                            name: p.name,
                                            displayName: p.displayName,
                                            interface: p.interface,
                                            enabled: p.enabled
                                        };
                                        if (p.connectCmd && p.connectCmd.length > 0) {
                                            reconstructed.connectCmd = p.connectCmd;
                                        }
                                        if (p.disconnectCmd && p.disconnectCmd.length > 0) {
                                            reconstructed.disconnectCmd = p.disconnectCmd;
                                        }
                                        providers.push(reconstructed);
                                    }
                                }
                                GlobalConfig.utilities.vpn.provider = providers;
                            }
                        }

                        MaterialIcon {
                            id: deleteIcon

                            anchors.centerIn: parent
                            text: "delete"
                            color: Colours.palette.m3onSurface
                        }
                    }
                }
            }
        }
    }

    Popup {
        id: vpnDialog

        property string currentState: "selection"
        property int editIndex: -1
        property string providerName: ""
        property string displayName: ""
        property string interfaceName: ""
        property string connectCmd: ""
        property string disconnectCmd: ""

        function showProviderSelection(): void {
            currentState = "selection";
            open();
        }

        function closeWithAnimation(): void {
            close();
        }

        function showAddForm(providerType: string, defaultDisplayName: string): void {
            editIndex = -1;
            providerName = providerType;
            displayName = defaultDisplayName;
            interfaceName = "";
            connectCmd = "";
            disconnectCmd = "";

            if (currentState === "selection") {
                transitionToForm.start();
            } else {
                currentState = "form";
                isClosing = false;
                open();
            }
        }

        function showEditForm(index: int): void {
            const provider = GlobalConfig.utilities.vpn.provider[index];
            const isObject = typeof provider === "object";

            editIndex = index;
            providerName = isObject ? (provider.name || "custom") : String(provider);
            displayName = isObject ? (provider.displayName || providerName) : providerName;
            interfaceName = isObject ? (provider.interface || "") : "";
            connectCmd = isObject && provider.connectCmd ? provider.connectCmd.join(" ") : "";
            disconnectCmd = isObject && provider.disconnectCmd ? provider.disconnectCmd.join(" ") : "";

            currentState = "form";
            open();
        }

        parent: Overlay.overlay
        x: Math.round((parent.width - width) / 2)
        y: Math.round((parent.height - height) / 2)
        implicitWidth: Math.min(400, parent.width - Tokens.padding.extraLargeIncreased)
        padding: Tokens.padding.large * 1.5

        modal: true
        closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside

        opacity: 0
        scale: 0.7

        enter: Transition {
            ParallelAnimation {
                Anim {
                    property: "opacity"
                    from: 0
                    to: 1
                    type: Anim.Emphasized
                }
                Anim {
                    property: "scale"
                    from: 0.7
                    to: 1
                    type: Anim.Emphasized
                }
            }
        }

        exit: Transition {
            ParallelAnimation {
                Anim {
                    property: "opacity"
                    from: 1
                    to: 0
                    type: Anim.EmphasizedSmall
                }
                Anim {
                    property: "scale"
                    from: 1
                    to: 0.7
                    type: Anim.EmphasizedSmall
                }
            }
        }

        Overlay.modal: Rectangle {
            color: Qt.rgba(0, 0, 0, 0.4 * vpnDialog.opacity)
        }

        onClosed: {
            currentState = "selection";
        }

        background: StyledRect {
            color: Colours.palette.m3surfaceContainerHigh
            radius: Tokens.rounding.extraLarge

            Elevation {
                anchors.fill: parent
                radius: parent.radius
                level: 3
                z: -1
            }

            Behavior on implicitHeight {
                Anim {
                    type: Anim.Emphasized
                }
            }
        }

        contentItem: Item {
            implicitHeight: vpnDialog.currentState === "selection" ? selectionContent.implicitHeight : formContent.implicitHeight

            Behavior on implicitHeight {
                Anim {
                    type: Anim.Emphasized
                }
            }

            ColumnLayout {
                id: selectionContent

                anchors.fill: parent
                spacing: Tokens.spacing.medium
                visible: vpnDialog.currentState === "selection"
                opacity: vpnDialog.currentState === "selection" ? 1 : 0

                Behavior on opacity {
                    Anim {
                        type: Anim.EmphasizedSmall
                    }
                }

                StyledText {
                    text: qsTr("Add VPN Provider")
                    font: Tokens.font.body.builders.large.weight(Font.Medium).build()
                }

                StyledText {
                    Layout.fillWidth: true
                    text: qsTr("Choose a provider to add")
                    wrapMode: Text.WordWrap
                    color: Colours.palette.m3outline
                    font: Tokens.font.body.small
                }

                TextButton {
                    Layout.topMargin: Tokens.spacing.medium
                    Layout.fillWidth: true
                    text: qsTr("NetBird")
                    inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                    inactiveOnColour: Colours.palette.m3onSurface
                    onClicked: {
                        const providers = [];
                        for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                            providers.push(GlobalConfig.utilities.vpn.provider[i]);
                        }
                        providers.push({
                            name: "netbird",
                            displayName: "NetBird",
                            interface: "wt0"
                        });
                        GlobalConfig.utilities.vpn.provider = providers;
                        vpnDialog.closeWithAnimation();
                    }
                }

                TextButton {
                    Layout.fillWidth: true
                    text: qsTr("Tailscale")
                    inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                    inactiveOnColour: Colours.palette.m3onSurface
                    onClicked: {
                        const providers = [];
                        for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                            providers.push(GlobalConfig.utilities.vpn.provider[i]);
                        }
                        providers.push({
                            name: "tailscale",
                            displayName: "Tailscale",
                            interface: "tailscale0"
                        });
                        GlobalConfig.utilities.vpn.provider = providers;
                        vpnDialog.closeWithAnimation();
                    }
                }

                TextButton {
                    Layout.fillWidth: true
                    text: qsTr("Cloudflare WARP")
                    inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                    inactiveOnColour: Colours.palette.m3onSurface
                    onClicked: {
                        const providers = [];
                        for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                            providers.push(GlobalConfig.utilities.vpn.provider[i]);
                        }
                        providers.push({
                            name: "warp",
                            displayName: "Cloudflare WARP",
                            interface: "CloudflareWARP"
                        });
                        GlobalConfig.utilities.vpn.provider = providers;
                        vpnDialog.closeWithAnimation();
                    }
                }

                TextButton {
                    Layout.fillWidth: true
                    text: qsTr("WireGuard")
                    inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                    inactiveOnColour: Colours.palette.m3onSurface
                    onClicked: {
                        vpnDialog.showAddForm("wireguard", "WireGuard");
                    }
                }

                TextButton {
                    Layout.fillWidth: true
                    text: qsTr("Custom")
                    inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                    inactiveOnColour: Colours.palette.m3onSurface
                    onClicked: {
                        vpnDialog.showAddForm("custom", "Custom VPN");
                    }
                }

                TextButton {
                    Layout.topMargin: Tokens.spacing.medium
                    Layout.fillWidth: true
                    text: qsTr("Cancel")
                    inactiveColour: Colours.palette.m3secondaryContainer
                    inactiveOnColour: Colours.palette.m3onSecondaryContainer
                    onClicked: vpnDialog.closeWithAnimation()
                }
            }

            ColumnLayout {
                id: formContent

                anchors.fill: parent
                spacing: Tokens.spacing.medium
                visible: vpnDialog.currentState === "form"
                opacity: vpnDialog.currentState === "form" ? 1 : 0

                Behavior on opacity {
                    Anim {
                        type: Anim.EmphasizedSmall
                    }
                }

                StyledText {
                    text: vpnDialog.editIndex >= 0 ? qsTr("Edit VPN Provider") : qsTr("Add %1 VPN").arg(vpnDialog.displayName)
                    font: Tokens.font.body.builders.large.weight(Font.Medium).build()
                }

                ColumnLayout {
                    Layout.fillWidth: true
                    spacing: Tokens.spacing.medium / 2

                    StyledText {
                        text: qsTr("Display Name")
                        font: Tokens.font.body.small
                        color: Colours.palette.m3onSurfaceVariant
                    }

                    StyledRect {
                        Layout.fillWidth: true
                        implicitHeight: 40
                        color: displayNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2)
                        radius: Tokens.rounding.medium
                        border.width: 1
                        border.color: displayNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3)

                        Behavior on color {
                            CAnim {}
                        }
                        Behavior on border.color {
                            CAnim {}
                        }

                        StyledTextField {
                            id: displayNameField

                            anchors.centerIn: parent
                            width: parent.width - Tokens.padding.medium
                            horizontalAlignment: TextInput.AlignLeft
                            text: vpnDialog.displayName
                            onTextChanged: vpnDialog.displayName = text
                        }
                    }
                }

                ColumnLayout {
                    Layout.fillWidth: true
                    spacing: Tokens.spacing.medium / 2

                    StyledText {
                        text: qsTr("Interface (e.g., wg0, torguard)")
                        font: Tokens.font.body.small
                        color: Colours.palette.m3onSurfaceVariant
                    }

                    StyledRect {
                        Layout.fillWidth: true
                        implicitHeight: 40
                        color: interfaceNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2)
                        radius: Tokens.rounding.medium
                        border.width: 1
                        border.color: interfaceNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3)

                        Behavior on color {
                            CAnim {}
                        }
                        Behavior on border.color {
                            CAnim {}
                        }

                        StyledTextField {
                            id: interfaceNameField

                            anchors.centerIn: parent
                            width: parent.width - Tokens.padding.medium
                            horizontalAlignment: TextInput.AlignLeft
                            text: vpnDialog.interfaceName
                            onTextChanged: vpnDialog.interfaceName = text
                        }
                    }
                }

                ColumnLayout {
                    Layout.fillWidth: true
                    spacing: Tokens.spacing.medium / 2
                    visible: vpnDialog.editIndex >= 0 ? (vpnDialog.connectCmd.length > 0) : (vpnDialog.providerName === "custom")

                    StyledText {
                        text: qsTr("Connect Command (e.g., wg-quick up wg0)")
                        font: Tokens.font.body.small
                        color: Colours.palette.m3onSurfaceVariant
                    }

                    StyledRect {
                        Layout.fillWidth: true
                        implicitHeight: 40
                        color: connectCmdField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2)
                        radius: Tokens.rounding.medium
                        border.width: 1
                        border.color: connectCmdField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3)

                        Behavior on color {
                            CAnim {}
                        }
                        Behavior on border.color {
                            CAnim {}
                        }

                        StyledTextField {
                            id: connectCmdField

                            anchors.centerIn: parent
                            width: parent.width - Tokens.padding.medium
                            horizontalAlignment: TextInput.AlignLeft
                            text: vpnDialog.connectCmd
                            onTextChanged: vpnDialog.connectCmd = text
                        }
                    }
                }

                ColumnLayout {
                    Layout.fillWidth: true
                    spacing: Tokens.spacing.medium / 2
                    visible: vpnDialog.editIndex >= 0 ? (vpnDialog.connectCmd.length > 0) : (vpnDialog.providerName === "custom")

                    StyledText {
                        text: qsTr("Disconnect Command (e.g., wg-quick down wg0)")
                        font: Tokens.font.body.small
                        color: Colours.palette.m3onSurfaceVariant
                    }

                    StyledRect {
                        Layout.fillWidth: true
                        implicitHeight: 40
                        color: disconnectCmdField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2)
                        radius: Tokens.rounding.medium
                        border.width: 1
                        border.color: disconnectCmdField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3)

                        Behavior on color {
                            CAnim {}
                        }
                        Behavior on border.color {
                            CAnim {}
                        }

                        StyledTextField {
                            id: disconnectCmdField

                            anchors.centerIn: parent
                            width: parent.width - Tokens.padding.medium
                            horizontalAlignment: TextInput.AlignLeft
                            text: vpnDialog.disconnectCmd
                            onTextChanged: vpnDialog.disconnectCmd = text
                        }
                    }
                }

                RowLayout {
                    Layout.topMargin: Tokens.spacing.medium
                    Layout.fillWidth: true
                    spacing: Tokens.spacing.medium

                    TextButton {
                        Layout.fillWidth: true
                        text: qsTr("Cancel")
                        inactiveColour: Colours.tPalette.m3surfaceContainerHigh
                        inactiveOnColour: Colours.palette.m3onSurface
                        onClicked: vpnDialog.closeWithAnimation()
                    }

                    TextButton {
                        Layout.fillWidth: true
                        text: qsTr("Save")
                        enabled: {
                            const hasCommands = vpnDialog.connectCmd.length > 0 || vpnDialog.disconnectCmd.length > 0;
                            if (hasCommands) {
                                return vpnDialog.interfaceName.length > 0 && vpnDialog.connectCmd.length > 0 && vpnDialog.disconnectCmd.length > 0;
                            }
                            return vpnDialog.interfaceName.length > 0;
                        }
                        inactiveColour: Colours.palette.m3primaryContainer
                        inactiveOnColour: Colours.palette.m3onPrimaryContainer

                        onClicked: {
                            const providers = [];
                            const hasCommands = vpnDialog.connectCmd.length > 0 && vpnDialog.disconnectCmd.length > 0;
                            const newProvider = {
                                displayName: vpnDialog.displayName || vpnDialog.interfaceName,
                                enabled: false,
                                interface: vpnDialog.interfaceName,
                                name: vpnDialog.providerName
                            };

                            if (hasCommands) {
                                newProvider.connectCmd = vpnDialog.connectCmd.split(" ").filter(s => s.length > 0);
                                newProvider.disconnectCmd = vpnDialog.disconnectCmd.split(" ").filter(s => s.length > 0);
                            }

                            if (vpnDialog.editIndex >= 0) {
                                const oldProvider = GlobalConfig.utilities.vpn.provider[vpnDialog.editIndex];
                                if (typeof oldProvider === "object" && oldProvider.enabled !== undefined) {
                                    newProvider.enabled = oldProvider.enabled;
                                }

                                for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                                    if (i === vpnDialog.editIndex) {
                                        providers.push(newProvider);
                                    } else {
                                        providers.push(GlobalConfig.utilities.vpn.provider[i]);
                                    }
                                }
                            } else {
                                for (let i = 0; i < GlobalConfig.utilities.vpn.provider.length; i++) {
                                    providers.push(GlobalConfig.utilities.vpn.provider[i]);
                                }
                                providers.push(newProvider);
                            }

                            GlobalConfig.utilities.vpn.provider = providers;
                            vpnDialog.closeWithAnimation();
                        }
                    }
                }
            }
        }

        SequentialAnimation {
            id: transitionToForm

            ParallelAnimation {
                Anim {
                    target: selectionContent
                    property: "opacity"
                    to: 0
                    type: Anim.EmphasizedSmall
                }
            }

            ScriptAction {
                script: {
                    vpnDialog.currentState = "form";
                }
            }

            ParallelAnimation {
                Anim {
                    target: formContent
                    property: "opacity"
                    to: 1
                    type: Anim.EmphasizedSmall
                }
            }
        }
    }
}
