import argparse
import os
import re
import subprocess
import sys
from pathlib import Path

HERE = Path(__file__).resolve().parent
PROJECT_ROOT = HERE.parent

IS_GITHUB = "GITHUB_ACTIONS" in os.environ


def run_command(
    cmd_list: list[str], shell: bool = False, check=False, capture_output: bool = False
) -> str | None:
    check = check if check is not None else check
    cmd = cmd_list if not shell else subprocess.list2cmdline(cmd_list)

    result: subprocess.CompletedProcess = subprocess.run(
        cmd, capture_output=capture_output, text=True, shell=shell, check=check
    )

    if not capture_output:
        return None

    stdout: str = result.stdout
    stdout = stdout.strip()
    return stdout


def parse_args():
    parser = argparse.ArgumentParser(
        description="Check compiled program size for a board"
    )
    parser.add_argument("board", help="Board name")
    parser.add_argument(
        "--max-size", type=int, required=False, help="Maximum allowed size"
    )
    parser.add_argument(
        "--no-build",
        action="store_true",
        help="Skip compilation and check existing build",
    )
    parser.add_argument(
        "--example",
        default="Blink",
        help="Example to compile (default: Blink)",
    )

    # Parse known args first
    args, unknown = parser.parse_known_args()

    # Add remaining arguments as extra_args
    args.extra_args = unknown

    return args


def main():
    os.chdir(str(PROJECT_ROOT))
    args = parse_args()

    if not args.no_build:
        cmd_list = [
            "uv",
            "run",
            "ci/ci-compile.py",
            args.board,
            "--examples",
            args.example,
        ] + args.extra_args
        try:
            run_command(cmd_list, shell=True, capture_output=IS_GITHUB, check=True)
        except subprocess.CalledProcessError:
            run_command(cmd_list, shell=True, capture_output=False, check=True)

    output = run_command(
        ["uv", "run", "ci/compiled_size.py", "--board", args.board],
        capture_output=True,
    )
    size_match = re.search(r": *(\d+)", output)  # type: ignore

    if not size_match:
        print("Error: Unable to extract size from output")
        print(f"Output: {output}")
        sys.exit(1)

    size = int(size_match.group(1))

    if args.max_size is not None and args.max_size > 0:
        max_size = args.max_size
        if size > max_size:
            print(f"{args.board} size {size} is greater than max size {max_size}")
            print("::error::Compiled size exceeds maximum allowed size")
            sys.exit(1)
        else:
            print(f"{args.board} size {size} is within the limit of {max_size}")
    else:
        if not args.max_size:
            print("Warning: No max size specified")
        elif args.max_size <= 0:
            print("Warning: max size was <= 0 so no check was performed")
        print(f"{args.board} size: {size}")


if __name__ == "__main__":
    main()
