#!/usr/bin/env python3
# ===----------------------------------------------------------------------===##
#
# This source file is part of the Swift open source project
#
# Copyright (c) 2025 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ===----------------------------------------------------------------------===##

import argparse
import logging
import os
import pathlib
import platform
import shlex
import sys
import typing as t

from helpers import (
    Configuration,
    change_directory,
    call,
    call_output,
)

logging.basicConfig(
    format=" | ".join(
        [
            # Prefix script name to the log in an attempt to avoid confusion when parsing logs
            f"{pathlib.Path(sys.argv[0]).name}",
            "%(asctime)s",
            "%(levelname)-8s",
            "%(module)s",
            "%(funcName)s",
            "Line:%(lineno)d",
            "%(message)s",
        ]
    ),
    level=logging.INFO,
)


REPO_ROOT_PATH = pathlib.Path(__file__).parent.parent.resolve()


def get_arguments() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    parser.add_argument(
        "-v",
        "--verbose",
        dest="is_verbose",
        action="store_true",
        help="When set, prints verbose information.",
    )
    parser.add_argument(
        "-c",
        "--configuration",
        type=Configuration,
        dest="config",
        default="debug",
        choices=[e.value for e in Configuration],
        help="The configuraiton to use.",
    )
    parser.add_argument(
        "--enable-swift-testing",
        action="store_true",
    )
    parser.add_argument(
        "--enable-xctest",
        action="store_true",
    )
    args = parser.parse_args()
    return args


def log_environment() -> None:
    logging.info("Environment Variables")
    for key, value in sorted(os.environ.items()):
        logging.info("  --> %s=%r", key, value)


def get_swiftpm_bin_dir(config: Configuration) -> pathlib.Path:
    logging.info("Retrieving Swift PM binary directory.")
    swiftpm_bin_dir = pathlib.Path(
        call_output(["swift", "build", "--configuration", config, "--show-bin-path"])
    )
    logging.info("SwiftPM BIN DIR: %s", swiftpm_bin_dir)
    return swiftpm_bin_dir


def is_on_darwin() -> bool:
    return platform.uname().system == "Darwin"


def set_environment(*, swiftpm_bin_dir: pathlib.Path,) -> None:
    os.environ["SWIFTCI_IS_SELF_HOSTED"] = "1"

    # Set the SWIFTPM_CUSTOM_BIN_DIR path
    os.environ["SWIFTPM_CUSTOM_BIN_DIR"] = str(swiftpm_bin_dir)

    # Ensure SDKROOT is configure
    if is_on_darwin():
        sdk_root = call_output(shlex.split("xcrun --show-sdk-path --sdk macosx"))
        logging.debug("macos sdk root = %r", sdk_root)
        os.environ["SDKROOT"] = sdk_root
    log_environment()


def run_bootstrap(swiftpm_bin_dir: pathlib.Path) -> None:
    logging.info("Current working directory is %s", pathlib.Path.cwd())
    logging.info("Bootstrapping with the XCBuild codepath...")
    call(
        [
            REPO_ROOT_PATH / "Utilities" / "bootstrap",
            "build",
            "--release",
            "--verbose",
            "--cross-compile-hosts",
            "macosx-arm64",
            "--skip-cmake-bootstrap",
            "--swift-build-path",
            (swiftpm_bin_dir / "swift-build").resolve(),
        ],
    )


def main() -> None:
    args = get_arguments()
    ignore = "-Xlinker /ignore:4217" if os.name == "nt" else ""
    logging.getLogger().setLevel(logging.DEBUG if args.is_verbose else logging.INFO)
    logging.debug("Args: %r", args)

    with change_directory(REPO_ROOT_PATH):
        swiftpm_bin_dir = get_swiftpm_bin_dir(config=args.config)
        set_environment(swiftpm_bin_dir=swiftpm_bin_dir)

        call(
            shlex.split("swift --version"),
        )

        call(
            shlex.split("swift package update"),
        )
        call(
            shlex.split(f"swift build --configuration {args.config} {ignore}"),
        )

        if os.name != "nt":
            swift_testing_arg= "--enable-swift-testing" if args.enable_swift_testing else ""
            xctest_arg= "--enable-xctest" if args.enable_swift_testing else ""
            call(
                shlex.split(f"swift run swift-test --configuration {args.config} --parallel {swift_testing_arg} {xctest_arg} --scratch-path .test {ignore}"),
            )

    if is_on_darwin():
        run_bootstrap(swiftpm_bin_dir=swiftpm_bin_dir)
    logging.info("Done")


if __name__ == "__main__":
    main()
