using System;
using System.Globalization;
using System.IO;

public class BatteryStatus
{
    public bool Present;
    public int  Percent = -1;
    public bool Charging;
    public bool Full;
}

public static class BatteryMonitor
{
    private const string Root = "/sys/class/power_supply";
    private static string _path;   // cached battery directory

    public static BatteryStatus Read()
    {
        var s = new BatteryStatus();

        string dir = FindBattery();
        if (dir == null) return s;

        int pct = ReadPercent(dir);
        if (pct < 0) return s;

        string status = ReadValue(dir, "status") ?? "Unknown";

        s.Present  = true;
        s.Percent  = Math.Max(0, Math.Min(100, pct));
        s.Charging = string.Equals(status, "Charging", StringComparison.OrdinalIgnoreCase);
        s.Full     = string.Equals(status, "Full",     StringComparison.OrdinalIgnoreCase);
        return s;
    }

    private static string FindBattery()
    {
        if (_path != null && Directory.Exists(_path)) return _path;
        _path = null;

        if (!Directory.Exists(Root)) return null;

        try
        {
            foreach (string dir in Directory.GetDirectories(Root))
            {
                if (!string.Equals(ReadValue(dir, "type"), "Battery",
                                   StringComparison.OrdinalIgnoreCase)) continue;

                // "scope" is Device on peripherals (stylus, BT mouse) — skip those
                string scope = ReadValue(dir, "scope");
                if (scope != null && !string.Equals(scope, "System",
                                   StringComparison.OrdinalIgnoreCase)) continue;

                if (ReadPercent(dir) < 0) continue;

                _path = dir;
                break;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Battery scan failed: " + ex.Message);
        }

        return _path;
    }

    private static int ReadPercent(string dir)
    {
        long pct = ParseLong(ReadValue(dir, "capacity"));
        if (pct >= 0) return (int)pct;

        // some firmwares expose energy/charge only
        long now  = ParseLong(ReadValue(dir, "energy_now"));
        long full = ParseLong(ReadValue(dir, "energy_full"));
        if (now < 0 || full <= 0)
        {
            now  = ParseLong(ReadValue(dir, "charge_now"));
            full = ParseLong(ReadValue(dir, "charge_full"));
        }
        if (now >= 0 && full > 0) return (int)Math.Round(now * 100.0 / full);

        return -1;
    }

    private static string ReadValue(string dir, string file)
    {
        try
        {
            string p = Path.Combine(dir, file);
            return File.Exists(p) ? File.ReadAllText(p).Trim() : null;
        }
        catch { return null; }
    }

    private static long ParseLong(string s)
    {
        long v;
        if (s != null && long.TryParse(s, NumberStyles.Integer,
                                       CultureInfo.InvariantCulture, out v)) return v;
        return -1;
    }
}