pragma Singleton
pragma ComponentBehavior: Bound

import QtQuick
import Quickshell
import Quickshell.Services.UPower
import qs.Common

Singleton {
    id: root

    property bool suppressSound: true
    property bool previousPluggedState: false

    readonly property var scale: 100 / SettingsData.batteryChargeLimit

    Timer {
        id: startupTimer
        interval: 500
        repeat: false
        running: true
        onTriggered: root.suppressSound = false
    }

    readonly property string preferredBatteryOverride: Quickshell.env("DMS_PREFERRED_BATTERY")

    // List of laptop batteries
    readonly property var batteries: UPower.devices.values.filter(dev => dev.isLaptopBattery)

    readonly property bool usePreferred: preferredBatteryOverride && preferredBatteryOverride.length > 0

    // Main battery (for backward compatibility)
    readonly property UPowerDevice device: {
        var preferredDev;
        if (usePreferred) {
            preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase()));
        }
        return preferredDev || batteries[0] || null;
    }
    // Whether at least one battery is available
    readonly property bool batteryAvailable: batteries.length > 0
    // Aggregated charge level (percentage)
    readonly property real batteryLevel: {
        if (!batteryAvailable)
            return 0;
        if (batteryCapacity === 0) {
            if (usePreferred && device && device.ready)
                return Math.round(device.percentage * 100 * scale);
            const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0);
            if (validBatteries.length === 0)
                return 0;
            const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length;
            return Math.round(avgPercentage * 100 * scale);
        }
        return Math.round((batteryEnergy * 100) / batteryCapacity * scale);
    }
    readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)

    // Is the system plugged in (Is not running on battery)
    readonly property bool isPluggedIn: !UPower.onBattery
    readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20

    onIsPluggedInChanged: {
        if (suppressSound || !batteryAvailable) {
            previousPluggedState = isPluggedIn;
            return;
        }

        if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) {
            if (isPluggedIn && !previousPluggedState) {
                AudioService.playPowerPlugSound();
            } else if (!isPluggedIn && previousPluggedState) {
                AudioService.playPowerUnplugSound();
            }
        }

        const profileValue = BatteryService.isPluggedIn ? SettingsData.acProfileName : SettingsData.batteryProfileName;

        if (profileValue !== "") {
            const targetProfile = parseInt(profileValue);
            if (!isNaN(targetProfile) && PowerProfiles.profile !== targetProfile) {
                PowerProfiles.profile = targetProfile;
            }
        }

        previousPluggedState = isPluggedIn;
    }

    // Aggregated charge/discharge rate
    readonly property real changeRate: {
        if (!batteryAvailable)
            return 0;
        if (usePreferred && device && device.ready)
            return device.changeRate;
        return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0;
    }

    // Aggregated battery health
    readonly property string batteryHealth: {
        if (!batteryAvailable)
            return "N/A";

        // If a preferred battery is selected and ready
        if (usePreferred && device && device.ready && device.healthSupported)
            return `${Math.round(device.healthPercentage)}%`;

        // Otherwise, calculate the average health of all laptop batteries
        const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0);
        if (validBatteries.length === 0)
            return "N/A";

        const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length;
        return `${Math.round(avgHealth)}%`;
    }

    readonly property real batteryEnergy: {
        if (!batteryAvailable)
            return 0;
        if (usePreferred && device && device.ready)
            return device.energy;
        return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0;
    }

    // Total battery capacity (Wh)
    readonly property real batteryCapacity: {
        if (!batteryAvailable)
            return 0;
        if (usePreferred && device && device.ready)
            return device.energyCapacity;
        return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0;
    }

    function translateBatteryState(state) {
        switch (state) {
        case UPowerDeviceState.Charging:
            return I18n.tr("Charging", "battery status");
        case UPowerDeviceState.Discharging:
            return I18n.tr("Discharging", "battery status");
        case UPowerDeviceState.Empty:
            return I18n.tr("Empty", "battery status");
        case UPowerDeviceState.FullyCharged:
            return I18n.tr("Fully Charged", "battery status");
        case UPowerDeviceState.PendingCharge:
            return I18n.tr("Pending Charge", "battery status");
        case UPowerDeviceState.PendingDischarge:
            return I18n.tr("Pending Discharge", "battery status");
        default:
            return I18n.tr("Unknown", "battery status");
        }
    }

    // Aggregated battery status
    readonly property string batteryStatus: {
        if (!batteryAvailable) {
            return I18n.tr("No Battery", "battery status");
        }

        if (isCharging && !batteries.some(b => b.changeRate > 0))
            return I18n.tr("Plugged In", "battery status");

        const states = batteries.map(b => b.state);
        if (states.every(s => s === states[0]))
            return translateBatteryState(states[0]);

        return isCharging ? I18n.tr("Charging", "battery status") : (isPluggedIn ? I18n.tr("Plugged In", "battery status") : I18n.tr("Discharging", "battery status"));
    }

    readonly property bool suggestPowerSaver: false

    readonly property var bluetoothDevices: {
        const btDevices = [];
        const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers];

        for (var i = 0; i < UPower.devices.count; i++) {
            const dev = UPower.devices.get(i);
            if (dev && dev.ready && bluetoothTypes.includes(dev.type)) {
                btDevices.push({
                    "name": dev.model || UPowerDeviceType.toString(dev.type),
                    "percentage": Math.round(dev.percentage * 100),
                    "type": dev.type
                });
            }
        }
        return btDevices;
    }

    // Format time remaining for charge/discharge
    function formatTimeRemaining() {
        if (!batteryAvailable) {
            return "Unknown";
        }

        let totalTime = 0;
        totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate);
        const avgTime = Math.abs(totalTime * 3600);
        if (!avgTime || avgTime <= 0 || avgTime > 86400)
            return "Unknown";

        const hours = Math.floor(avgTime / 3600);
        const minutes = Math.floor((avgTime % 3600) / 60);
        return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
    }

    function getBatteryIcon() {
        if (!batteryAvailable) {
            return "power";
        }

        if (isCharging) {
            if (batteryLevel >= 90) {
                return "battery_charging_full";
            }
            if (batteryLevel >= 80) {
                return "battery_charging_90";
            }
            if (batteryLevel >= 60) {
                return "battery_charging_80";
            }
            if (batteryLevel >= 50) {
                return "battery_charging_60";
            }
            if (batteryLevel >= 30) {
                return "battery_charging_50";
            }
            if (batteryLevel >= 20) {
                return "battery_charging_30";
            }
            return "battery_charging_20";
        }
        if (isPluggedIn) {
            if (batteryLevel >= 90) {
                return "battery_charging_full";
            }
            if (batteryLevel >= 80) {
                return "battery_charging_90";
            }
            if (batteryLevel >= 60) {
                return "battery_charging_80";
            }
            if (batteryLevel >= 50) {
                return "battery_charging_60";
            }
            if (batteryLevel >= 30) {
                return "battery_charging_50";
            }
            if (batteryLevel >= 20) {
                return "battery_charging_30";
            }
            return "battery_charging_20";
        }
        if (batteryLevel >= 95) {
            return "battery_full";
        }
        if (batteryLevel >= 85) {
            return "battery_6_bar";
        }
        if (batteryLevel >= 70) {
            return "battery_5_bar";
        }
        if (batteryLevel >= 55) {
            return "battery_4_bar";
        }
        if (batteryLevel >= 40) {
            return "battery_3_bar";
        }
        if (batteryLevel >= 25) {
            return "battery_2_bar";
        }
        return "battery_1_bar";
    }
}
