import os
import time
import json
import socket
import struct
import subprocess
import urllib.request
from pathlib import Path
from warehouse import Vpn_cache, Media_flag

class Cached:
    def __init__(self, ttl):
        self.ttl = ttl
        self.last = 0
        self.value = ""

    def get(self, fn):
        now = time.time()
        if now - self.last >= self.ttl:
            try:
                self.value = fn()
            except Exception:
                self.value = ""
            self.last = now
        return self.value


def http_get(url, timeout=2):
    try:
        with urllib.request.urlopen(url, timeout=timeout) as r:
            return r.read().decode().strip()
    except Exception:
        return ""


class StatusBar:
    def __init__(self):
        self.cpu = Cached(5)
        self.bat = Cached(5)
        self.vpn = Cached(60)
        self.rec = Cached(1)

    def run(self, cmd):
        return subprocess.run(cmd, capture_output=True, text=True).stdout.strip()

    def get_volume(self):
        return self.run(["pamixer", "--get-volume-human"])

    def get_ram(self):
        out = self.run(["free", "-m"]).splitlines()
        mem = next((l for l in out if l.startswith("Mem:")), "")
        parts = mem.split()
        if len(parts) < 7:
            return "?"
        total = int(parts[1])
        used = int(parts[2])
        return f"{used//1000}GB/{total//1000}GB"

    def get_cpu(self):
        def compute():
            try:
                out = self.run(["grep", "cpu ", "/proc/stat"])
                p = out.split()
                if len(p) < 8:
                    return "0.0%"
                user, nice, system, idle = map(int, p[1:5])
                total = user + nice + system + idle
                busy = total - idle
                return f"{(busy / total) * 100:.1f}%"
            except Exception:
                return "0.0%"

        return self.cpu.get(compute)

    def get_battery(self):
        def compute():
            bat = Path("/sys/class/power_supply/BAT0")
            if not bat.exists():
                return ""
            try:
                cap = (bat / "capacity").read_text().strip()
                status = (bat / "status").read_text().strip()
                return f"{cap}% ({status})"
            except Exception:
                return ""

        return self.bat.get(compute)

    def get_vpn(self):
        def compute():
            if not self.run(["wg", "show", "interfaces"]):
                if Vpn_cache.exists():
                    Vpn_cache.unlink()
                return ""

            country = ""
            if Vpn_cache.exists():
                country = Vpn_cache.read_text().strip()

            if not country:
                ip = http_get("https://ifconfig.me")
                geo = http_get(f"https://iplookup.stab.ing/api/v1/lookup?ip={ip}")

                if '"country"' in geo:
                    try:
                        country = geo.split('"country":"')[1].split('"')[0]
                    except Exception:
                        country = ""

                if country:
                    Vpn_cache.write_text(country)

            return f"VPN: {country or 'Unknown'}"

        return self.vpn.get(compute)

    def get_recording(self):
        def compute():
            return "RECORDING!" if self.run(["pgrep", "-x", "wf-recorder"]) else ""

        return self.rec.get(compute)

    def get_time(self):
        if Media_flag.exists():
            return "0001-01-01 12:00 AM"
        return self.run(["date", "+%Y-%m-%d %I:%M %p"])

    def render(self):
        vol = self.get_volume()
        ram = self.get_ram()
        cpu = self.get_cpu()
        bat = self.get_battery()
        vpn = self.get_vpn()
        rec = self.get_recording()
        t = self.get_time()

        extra = " / ".join([x for x in [rec, vpn, bat] if x])

        if extra:
            return f"CPU: {cpu} / RAM: {ram} / VOL: {vol} / {extra} / {t}"
        return f"CPU: {cpu} / RAM: {ram} / VOL: {vol} / {t}"


def main():
    bar = StatusBar()
    while True:
        print(bar.render(), flush=True)
        time.sleep(0.1)


if __name__ == "__main__":
    main()