import inspect
import platform
import re
import subprocess

sieve_factory_erat_indexed_cutoff = 800_000_000
on_disk_multiples_block_size = 25_000
multiples_factory_ondisk_inmem_cutoff = 1_000


def get_cache_size() -> int:
    os = platform.system()
    match os:
        case 'Darwin':
            return _get_darwin_cache_size()
        case 'Linux':
            # not tested, may raise
            return _untested_get_linux_cache_size()
        case 'Windows':
            raise NotImplementedError(f'not implemented for your operating system: {os}')
        case _:
            raise NotImplementedError(f'not implemented for your operating system: {os}')


def _untested_get_linux_cache_size() -> int | None:
    try:
        # Run the lscpu command and capture its output
        output = subprocess.run(['lscpu'], capture_output=True, text=True, check=True).stdout
        # The output format for L1d cache size typically looks like: "L1d cache:             32 KiB"
        matches = re.search(r'L1d cache:\s+([0-9.]+)\s+([KMGT]?iB)', output)
        if matches is not None:
            size_val = float(matches.group(1))
            exponent = 0
            match matches.group(2):
                # Convert to bytes for a consistent value
                case 'KiB':
                    exponent = 1
                case 'MiB':
                    exponent = 2
                case 'GiB':
                    exponent = 3
                case _:
                    pass  # already set to 0
            return int(size_val * 1024 ** exponent)
    except Exception as e:
        e.add_note(
            f'not implemented correctly for Linux\nhere is the offending code in __init__.py\n{"".join(inspect.getsourcelines(_get_linux_cache_size)[0])}')
        raise e


def _get_darwin_cache_size() -> int:
    raw_str = subprocess.run(['sysctl', 'hw.l1dcachesize'], capture_output=True, text=True, check=True).stdout
    return int(raw_str.strip().split(' ')[-1])
