import re
import subprocess
from logging import Logger


def runSubprocess(command: list, logger: Logger) -> str | None:
    """
    Helper function to run a subprocess and return the stdout.

    :param command: The command formated as a list.
    :param logger: The logger instance used for logging.
    :return: The stdout of the subprocess or None if the subprocess failed.
    """
    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    if process.returncode != 0:
        logger.error(
            f"Command {command} failed with return code: {process.returncode} and error: {stderr.decode()}"
        )
        return None
    else:
        return stdout.decode()


def gatherCPUCoreInfo(logger: Logger) -> int:
    """
    Extract the CPU information and returns the number of CPU cores.

    :return: Number of CPU cores
    """
    CAT = "/bin/cat"
    CPU_INFO = "/proc/cpuinfo"
    DEFAULT_CPU_CORES = 1
    PATTERN = r"processor[ \t]*:[ \t]+(\d+)"

    decodedStdOut = runSubprocess([CAT, CPU_INFO], logger)
    if decodedStdOut:
        results = re.findall(PATTERN, decodedStdOut)
        numberOfCores = len(results) if results else DEFAULT_CPU_CORES
        logger.info(f"Counted {numberOfCores} cores.")
        return numberOfCores
    else:
        logger.error(
            f"Failed to read CPU core infos, continue with {DEFAULT_CPU_CORES} CPU cores as default."
        )
        return DEFAULT_CPU_CORES


def gatherRAMInfo(logger: Logger) -> int:
    """
    Extract the RAM information and returns RAM size in MB.

    :return: RAM size in MB.
    """
    CAT = "/bin/cat"
    MEM_INFO = "/proc/meminfo"
    PATTERN = r"MemTotal[ \t]*:[ \t]+(\d+)"
    DEFAULT_RAM = 256  # in MB
    decodedStdOut = runSubprocess([CAT, MEM_INFO], logger)
    if decodedStdOut:
        results = re.findall(PATTERN, decodedStdOut)
        ramInMB = int(results[0]) // 1024 if results else DEFAULT_RAM
        logger.info(f"Found {ramInMB}MB RAM.")
        return ramInMB
    else:
        logger.error(
            f"Failed to read RAM infos, continue with default {DEFAULT_RAM}MB RAM."
        )
        return DEFAULT_RAM


def getMMDCRegister(logger: Logger) -> str:
    """
    Extract the MMDC register value from the uboot environment.

    :return: The register value as string.
    """
    FW_PRINTENV = "/usr/bin/fw_printenv"
    NAME = "mmdcx_mdctl"
    decodedStdOut = runSubprocess([FW_PRINTENV, "-n", NAME], logger)
    if decodedStdOut:
        return decodedStdOut.strip("\0\n")
    else:
        logger.error(f"Failed to read {NAME}, from uboot env.")
        return ""
