#!/usr/bin/python3

import sys
import os
import shutil
import subprocess
import glob
import argparse
from datetime import datetime


def parse_args():
    parser = argparse.ArgumentParser(description="BredOS System Reporter")
    parser.add_argument(
        "-l",
        "--local",
        action="store_true",
        help="Save report locally instead of uploading",
    )
    return parser.parse_args()


def installed(command) -> str | None:
    return shutil.which(command) is not None


def force_install(packages: list) -> None:
    if not packages:
        return

    print(f"Installing missing packages: {' '.join(packages)}")

    # Refresh pacman database in case of fresh install
    try:
        subprocess.run(
            ["pacman", "-Sy"],
            check=True,
        )
    except subprocess.CalledProcessError as e:
        print(f"Failed to update databases: {e}")
        sys.exit(1)

    # Install all missing
    try:
        subprocess.run(
            ["pacman", "-S", "--needed", "--noconfirm"] + packages,
            check=True,
        )
    except subprocess.CalledProcessError as e:
        print(f"Failed to install packages: {e}")
        sys.exit(1)


def run_command(command: str) -> str:
    try:
        result = subprocess.run(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            check=True,
        )
        return result.stdout
    except Exception as e:
        return f"Error running command '{' '.join(command)}': {e.stderr}"


def upload_to_termbin(data: str) -> str | None:
    try:
        process = subprocess.Popen(
            ["/usr/bin/nc", "termbin.com", "9999"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            text=True,
        )
        url, _ = process.communicate(input=data)
        if process.returncode == 0:
            return url.strip()
        else:
            print("Failed to upload data to termbin.")
            sys.exit(1)
    except Exception as e:
        print(f"Error uploading to termbin: {e}")
        sys.exit(1)


def save_to_file(data: str) -> str:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"{timestamp}_sys-report.txt"
    try:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(data)
        return os.path.abspath(filename)
    except Exception as e:
        print(f"Error saving report to file: {e}")
        sys.exit(1)


def check_root() -> bool:
    if os.geteuid() != 0:
        print("This script requires root privileges. Relaunching with sudo...")
        try:
            os.execvp("sudo", ["sudo"] + sys.argv)
        except Exception as e:
            print(f"Failed to relaunch with sudo: {e}", file=sys.stderr)
            sys.exit(1)
    return True


def get_serial_devices() -> list:
    devs = []
    for pattern in ["/dev/ttyACM*", "/dev/ttyUSB*", "/dev/ttyS*"]:
        devs.extend(glob.glob(pattern))
    return devs


def append_xorg_logs() -> str:
    log_paths = [
        "/var/log/Xorg.0.log",
        "/var/log/Xorg.0.log.old",
    ]

    xorg_data = "\n=== Xorg Logs ===\n"
    found = False

    for path in log_paths:
        if os.path.isfile(path):
            found = True
            xorg_data += f"\n--- Contents of {path} ---\n"
            try:
                with open(path, "r", encoding="utf-8", errors="replace") as f:
                    xorg_data += f.read()
            except Exception as e:
                xorg_data += f"Error reading {path}: {e}\n"
        else:
            xorg_data += f"\n{path} not found.\n"

    if not found:
        xorg_data += "No Xorg log files found on the system.\n"
    return xorg_data


def main() -> None:
    args = parse_args()
    check_root()

    progs = {
        "inxi": "inxi",
        "eglinfo": "mesa-utils",
        "lsusb": "usbutils",
        "lspci": "pciutils",
        "vulkaninfo": "vulkan-tools",
    }

    missing = [progs[i] for i in progs if not installed(i)]

    if not (installed("neofetch") or installed("fastfetch")):
        missing.append("fastfetch")

    if missing:
        force_install(missing)

    # Verify again after install
    for cmd in progs:
        if not installed(cmd):
            print(f"Error: required command '{cmd}' still missing after install.")
            sys.exit(1)

    fastfetch_installed = installed("/usr/bin/fastfetch")

    commands = [
        ["/usr/bin/lspci"],
        ["/usr/bin/lsusb"],
        ["/usr/bin/lsblk"],
        ["/usr/bin/df", "-h"],
        ["/usr/bin/lsmod"],
        ["/usr/bin/inxi", "-ezrmxxfiv", "8"],
        ["/usr/bin/env"],
        ["/usr/bin/pacman", "-Q"],
        ["/usr/bin/dmesg"],
        ["/usr/bin/lsusb", "-v"],
    ]

    if fastfetch_installed:
        commands.append(["/usr/bin/fastfetch", "--logo", "none", "--color", "0"])
    else:
        commands.append(["/usr/bin/neofetch", "--off"])

    debug_data = "BredOS System Reporter v1.5\n"

    for cmd in commands:
        debug_data += f"\n=== Output of {' '.join(cmd)} ===\n"
        print(f"Running {' '.join(cmd)}")
        debug_data += run_command(cmd)

    # Add serial devices listing from glob, no shell call
    debug_data += (
        "\n=== Serial devices matching /dev/ttyACM*, /dev/ttyUSB*, /dev/ttyS* ===\n"
    )
    serial_devices = get_serial_devices()
    if serial_devices:
        debug_data += "\n".join(serial_devices) + "\n"
    else:
        debug_data += "No serial devices found.\n"

    # Append Xorg logs for debugging display manager / X crashes
    debug_data += append_xorg_logs()

    if args.local:
        # Save to local file
        file_path = save_to_file(debug_data)
        print(f"Debug data saved to: {file_path}")
    else:
        # Upload to termbin as before
        url = upload_to_termbin(debug_data).replace("\n", "")
        print(
            f"Debug data uploaded successfully: {url}\n>>> This URL contains information about your system, which makes it easy for us to help you!"
        )

    print("Support: https://discord.gg/beSUnWGVH2")


if __name__ == "__main__":
    main()
