"""
Downloads the specified webdriver to "r_seleniumbase/drivers/"

Usage:
    sbase get {chromedriver|geckodriver|edgedriver|
               iedriver|uc_driver|cft|chs} [OPTIONS]
Options:
    VERSION         Specify the version.
                    Tries to detect the needed version.
                    If using chromedriver or edgedriver,
                    you can use the major version integer.
    -p OR --path    Also copy the driver to /usr/local/bin
Examples:
    sbase get chromedriver
    sbase get geckodriver
    sbase get edgedriver
    sbase get chromedriver 114
    sbase get chromedriver 114.0.5735.90
    sbase get chromedriver stable
    sbase get chromedriver beta
    sbase get chromedriver -p
    sbase get cft 131
    sbase get chs
Output:
    Downloads the webdriver to r_seleniumbase/drivers/
    (chromedriver is required for Chrome automation)
    (geckodriver is required for Firefox automation)
    (edgedriver is required for MS__Edge automation)
"""
import colorama
import logging
import os
import platform
import requests
import shutil
import subprocess
import sys
import time
import tarfile
import urllib3
import zipfile
from contextlib import suppress
from r_seleniumbase.fixtures import constants
from r_seleniumbase.fixtures import shared_utils
from r_seleniumbase import config as sb_config
from r_seleniumbase import drivers  # webdriver storage folder for r_seleniumbase

urllib3.disable_warnings()
ARCH = platform.architecture()[0]
IS_ARM_MAC = shared_utils.is_arm_mac()
IS_MAC = shared_utils.is_mac()
IS_LINUX = shared_utils.is_linux()
IS_WINDOWS = shared_utils.is_windows()
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
LOCAL_PATH = "/usr/local/bin/"  # On Mac and Linux systems
DEFAULT_CHROMEDRIVER_VERSION = "114.0.5735.90"  # (If can't find LATEST_STABLE)
DEFAULT_GECKODRIVER_VERSION = "v0.36.0"
DEFAULT_EDGEDRIVER_VERSION = "115.0.1901.183"  # (If can't find LATEST_STABLE)


def invalid_run_command():
    exp = "  ** get / install **\n\n"
    exp += "  Usage:\n"
    exp += "     r_seleniumbase install [DRIVER_NAME] [OPTIONS]\n"
    exp += "     OR     sbase install [DRIVER_NAME] [OPTIONS]\n"
    exp += "     OR  r_seleniumbase get [DRIVER_NAME] [OPTIONS]\n"
    exp += "     OR         sbase get [DRIVER_NAME] [OPTIONS]\n"
    exp += "         (Drivers: chromedriver, cft, uc_driver,\n"
    exp += "                   edgedriver, chs, geckodriver)\n"
    exp += "  Options:\n"
    exp += "     VERSION    Specify the version.\n"
    exp += "                Tries to detect the needed version.\n"
    exp += "                If using chromedriver or edgedriver,\n"
    exp += "                you can use the major version integer.\n"
    exp += "\n"
    exp += "     -p OR --path   Also copy the driver to /usr/local/bin\n"
    exp += "  Examples:\n"
    exp += "     sbase get chromedriver\n"
    exp += "     sbase get geckodriver\n"
    exp += "     sbase get edgedriver\n"
    exp += "     sbase get chromedriver 114\n"
    exp += "     sbase get chromedriver 114.0.5735.90\n"
    exp += "     sbase get chromedriver stable\n"
    exp += "     sbase get chromedriver beta\n"
    exp += "     sbase get chromedriver -p\n"
    exp += "     sbase get cft 131\n"
    exp += "     sbase get chs\n"
    exp += "  Output:\n"
    exp += "     Downloads the webdriver to r_seleniumbase/drivers/\n"
    exp += "     (chromedriver is required for Chrome automation)\n"
    exp += "     (geckodriver is required for Firefox automation)\n"
    exp += "     (edgedriver is required for MS__Edge automation)\n"
    exp += "     (cft is for the `Chrome for Testing` binary exe)\n"
    exp += "     (chs is for the `Chrome-Headless-Shell` binary.)\n"
    print("")
    raise Exception("%s\n\n%s" % (constants.Warnings.INVALID_RUN_COMMAND, exp))


def make_executable(file_path):
    # Set permissions to: "If you can read it, you can execute it."
    mode = os.stat(file_path).st_mode
    mode |= (mode & 0o444) >> 2  # copy R bits to X
    os.chmod(file_path, mode)


def get_proxy_info():
    use_proxy = None
    protocol = "http"
    proxy_string = None
    user_and_pass = None
    if " --proxy=" in " ".join(sys.argv):
        from r_seleniumbase.core import proxy_helper
        for arg in sys.argv:
            if arg.startswith("--proxy="):
                proxy_string = arg.split("--proxy=")[1]
                if "@" in proxy_string:
                    # Format => username:password@hostname:port
                    try:
                        user_and_pass = proxy_string.split("@")[0]
                        proxy_string = proxy_string.split("@")[1]
                    except Exception:
                        raise Exception(
                            "The format for using a proxy server with auth "
                            'is: "username:password@hostname:port". If not '
                            'using auth, the format is: "hostname:port".'
                        )
                if proxy_string.endswith(":443"):
                    protocol = "https"
                elif "socks4" in proxy_string:
                    protocol = "socks4"
                elif "socks5" in proxy_string:
                    protocol = "socks5"
                proxy_string = proxy_helper.validate_proxy_string(proxy_string)
                if user_and_pass:
                    proxy_string = "%s@%s" % (user_and_pass, proxy_string)
                use_proxy = True
                break
    return (use_proxy, protocol, proxy_string)


def requests_get(url):
    use_proxy, protocol, proxy_string = get_proxy_info()
    proxies = None
    response = None
    if use_proxy:
        proxies = {protocol: proxy_string}
    try:
        response = requests.get(url, proxies=proxies, timeout=1.25)
    except Exception:
        # Prevent SSLCertVerificationError / CERTIFICATE_VERIFY_FAILED
        url = url.replace("https://", "http://")
        time.sleep(0.04)
        response = requests.get(url, proxies=proxies, timeout=2.75)
    return response


def requests_get_with_retry(url):
    use_proxy, protocol, proxy_string = get_proxy_info()
    proxies = None
    response = None
    if use_proxy:
        proxies = {protocol: proxy_string}
    try:
        response = requests.get(url, proxies=proxies, timeout=1.35)
    except Exception:
        time.sleep(1)
        try:
            response = requests.get(url, proxies=proxies, timeout=2.45)
        except Exception:
            time.sleep(1)
            response = requests.get(url, proxies=proxies, timeout=3.55)
    return response


def get_cft_known_good_versions():
    if hasattr(sb_config, "cft_kgv_json") and sb_config.cft_kgv_json:
        return sb_config.cft_kgv_json
    cft_ngv_url = (
        "https://googlechromelabs.github.io/"
        "chrome-for-testing/known-good-versions.json"
    )
    sb_config.cft_kgv_json = requests_get(cft_ngv_url)
    return sb_config.cft_kgv_json


def get_cft_latest_versions_per_milestone():
    if hasattr(sb_config, "cft_lvpm_json") and sb_config.cft_lvpm_json:
        return sb_config.cft_lvpm_json
    cft_lvpm_url = (
        "https://googlechromelabs.github.io/"
        "chrome-for-testing/latest-versions-per-milestone.json"
    )
    sb_config.cft_lvpm_json = requests_get(cft_lvpm_url)
    return sb_config.cft_lvpm_json


def get_cft_latest_version_from_milestone(milestone):
    url_request = get_cft_latest_versions_per_milestone()
    return url_request.json()["milestones"][milestone]["version"]


def get_latest_chromedriver_version(channel="Stable"):
    try:
        if hasattr(sb_config, "cft_lkgv_json") and sb_config.cft_lkgv_json:
            return sb_config.cft_lkgv_json["channels"][channel]["version"]
        req = requests_get(
            "https://googlechromelabs.github.io/"
            "chrome-for-testing/last-known-good-versions.json"
        )
        if req and req.ok:
            sb_config.cft_lkgv_json = req.json()
            return req.json()["channels"][channel]["version"]
    except Exception:
        pass
    # If a problem with Chrome-for-Testing JSON API: Fall back
    return DEFAULT_CHROMEDRIVER_VERSION


def get_latest_stable_chromedriver_version():
    return get_latest_chromedriver_version(channel="Stable")


def get_latest_beta_chromedriver_version():
    return get_latest_chromedriver_version(channel="Beta")


def get_latest_dev_chromedriver_version():
    return get_latest_chromedriver_version(channel="Dev")


def get_latest_canary_chromedriver_version():
    return get_latest_chromedriver_version(channel="Canary")


def log_d(message):
    """If setting sb_config.settings.HIDE_DRIVER_DOWNLOADS to True,
    output from driver downloads are logged instead of printed."""
    if (
        hasattr(sb_config.settings, "HIDE_DRIVER_DOWNLOADS")
        and sb_config.settings.HIDE_DRIVER_DOWNLOADS
    ):
        logging.debug(message)
    else:
        print(message)


def main(override=None, intel_for_uc=None, force_uc=None):
    if override:
        found_proxy = None
        if hasattr(sb_config, "proxy_driver") and sb_config.proxy_driver:
            if " --proxy=" in " ".join(sys.argv):
                for arg in sys.argv:
                    if arg.startswith("--proxy="):
                        found_proxy = arg
                        break
        if override == "chromedriver":
            sys.argv = ["r_seleniumbase", "get", "chromedriver"]
        elif override.startswith("chromedriver "):
            extra = override.split("chromedriver ")[1]
            sys.argv = ["r_seleniumbase", "get", "chromedriver", extra]
        elif override == "edgedriver":
            sys.argv = ["r_seleniumbase", "get", "edgedriver"]
        elif override.startswith("edgedriver "):
            extra = override.split("edgedriver ")[1]
            sys.argv = ["r_seleniumbase", "get", "edgedriver", extra]
        elif override == "geckodriver":
            sys.argv = ["r_seleniumbase", "get", "geckodriver"]
        elif override.startswith("geckodriver "):
            extra = override.split("geckodriver ")[1]
            sys.argv = ["r_seleniumbase", "get", "geckodriver", extra]
        elif override == "iedriver":
            sys.argv = ["r_seleniumbase", "get", "iedriver"]
        elif override.startswith("iedriver "):
            extra = override.split("iedriver ")[1]
            sys.argv = ["r_seleniumbase", "get", "iedriver", extra]
        elif override == "cft":
            sys.argv = ["r_seleniumbase", "get", "cft"]
        elif override.startswith("cft "):
            extra = override.split("cft ")[1]
            sys.argv = ["r_seleniumbase", "get", "cft", extra]
        elif override == "chs":
            sys.argv = ["r_seleniumbase", "get", "chs"]
        elif override.startswith("chs "):
            extra = override.split("chs ")[1]
            sys.argv = ["r_seleniumbase", "get", "chs", extra]
        if found_proxy:
            sys.argv.append(found_proxy)

    num_args = len(sys.argv)
    if (
        "sbase" in sys.argv[0].lower()
        or ("r_seleniumbase" in sys.argv[0].lower())
    ):
        if num_args < 3 or num_args > 5:
            invalid_run_command()
    else:
        invalid_run_command()
    name = sys.argv[2].lower()
    if force_uc:
        name = "uc_driver"

    file_name = None
    download_url = None
    headless_ie_url = None
    headless_ie_exists = False
    headless_ie_file_name = None
    downloads_folder = DRIVER_DIR
    expected_contents = None
    platform_code = None
    copy_to_path = False
    latest_version = ""
    use_version = ""
    new_file = ""
    f_name = ""
    c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
    c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
    c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
    c4 = colorama.Fore.LIGHTRED_EX + colorama.Back.LIGHTWHITE_EX
    c5 = colorama.Fore.RED + colorama.Back.LIGHTWHITE_EX
    c6 = colorama.Fore.LIGHTYELLOW_EX + colorama.Back.CYAN
    cr = colorama.Style.RESET_ALL
    if IS_LINUX:
        c1 = ""
        c2 = ""
        c3 = ""
        c4 = ""
        c5 = ""
        c6 = ""
        cr = ""

    if name == "chromedriver" or name == "uc_driver":
        if name == "uc_driver" and IS_ARM_MAC:
            intel_for_uc = True  # uc_driver is generated from chromedriver
        last = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"
        use_version = DEFAULT_CHROMEDRIVER_VERSION  # Until get correct VER

        if (
            not override
            and (
                num_args == 3
                or (num_args == 4 and "-p" in sys.argv[3].lower())
            )
        ):
            major_chrome_version = None
            try:
                from r_seleniumbase.core import detect_b_ver

                br_app = "google-chrome"
                major_chrome_version = (
                    detect_b_ver.get_browser_version_from_os(br_app)
                ).split(".")[0]
                if int(major_chrome_version) < 72:
                    major_chrome_version = None
            except Exception:
                major_chrome_version = None
            if major_chrome_version and major_chrome_version.isnumeric():
                num_args += 1
                sys.argv.insert(3, major_chrome_version)

        get_latest = False
        get_v_latest = False
        get_previous = False
        get_beta = False
        get_canary = False
        if num_args == 4 or num_args == 5:
            if "-p" not in sys.argv[3].lower():
                use_version = sys.argv[3]
                uv_low = use_version.lower()
                if uv_low == "latest" or uv_low == "stable":
                    uv_low = "latest"  # If "stable", rename
                    get_latest = True
                elif uv_low == "latest-1" or uv_low == "previous":
                    uv_low = "latest-1"  # If "previous", rename
                    get_previous = True
                elif uv_low == "beta":
                    get_beta = True
                elif uv_low == "dev":
                    use_version = get_latest_dev_chromedriver_version()
                    sys.argv[3] = use_version
                elif uv_low == "canary":
                    get_canary = True
                elif uv_low.isdigit() and int(uv_low) > 69:
                    get_v_latest = True
            else:
                copy_to_path = True
        if num_args == 5:
            if "-p" in sys.argv[4].lower():
                copy_to_path = True
            else:
                invalid_run_command()
        if IS_MAC:
            if IS_ARM_MAC and not intel_for_uc:
                use_version = use_version.lower()
                if (
                    use_version == "latest"
                    or use_version == "stable"
                    or use_version == "latest-1"
                    or use_version == "previous"
                    or use_version == "beta"
                    or use_version == "canary"
                ):
                    use_version = get_latest_stable_chromedriver_version()
                if use_version == "latest-1" or use_version == "previous":
                    use_version = str(int(use_version.split(".")[0]) - 1)
                elif use_version == "beta":
                    use_version = str(int(use_version.split(".")[0]) + 1)
                elif use_version == "canary":
                    use_version = str(int(use_version.split(".")[0]) + 2)
            if (
                IS_ARM_MAC
                and not intel_for_uc
                and int(use_version.split(".")[0]) > 105
            ):
                file_name = "chromedriver_mac_arm64.zip"
            else:
                file_name = "chromedriver_mac64.zip"
        elif IS_LINUX:
            file_name = "chromedriver_linux64.zip"
        elif IS_WINDOWS:
            file_name = "chromedriver_win32.zip"  # Works for win32 / win_x64
            if not get_latest and not get_v_latest and num_args < 4:
                get_latest = True
        else:
            raise Exception(
                "Cannot determine which version of chromedriver to download!"
            )
        found_chromedriver = False
        cft = False
        if get_latest or get_previous or get_beta or get_canary:
            use_version = get_latest_stable_chromedriver_version()
            found_chromedriver = True
            if get_previous and int(use_version.split(".")[0]) >= 115:
                get_v_latest = True
                use_version = str(int(use_version.split(".")[0]) - 1)
            elif get_beta and int(use_version.split(".")[0]) >= 115:
                get_v_latest = True
                use_version = get_latest_beta_chromedriver_version()
                use_version = use_version.split(".")[0]
            elif get_canary and int(use_version.split(".")[0]) >= 115:
                get_v_latest = True
                use_version = get_latest_canary_chromedriver_version()
                use_version = use_version.split(".")[0]
        force_cft = False
        if (
            use_version.split(".")[0].isnumeric()
            and int(use_version.split(".")[0]) >= 115
        ):
            force_cft = True
        if (get_v_latest or force_cft):
            if get_v_latest:
                if not force_cft:
                    url_req = requests_get(last)
                    if url_req.ok:
                        latest_version = url_req.text
                else:
                    latest_version = get_latest_stable_chromedriver_version()
                force_cft = False
            if not force_cft and int(use_version) < 115:
                last = last + "_" + use_version
                url_request = requests_get(last)
                if url_request.ok:
                    found_chromedriver = True
                    use_version = url_request.text
                    if use_version == latest_version:
                        get_latest = True
            else:
                url_request = None
                cft = True
                if force_cft:
                    url_request = get_cft_known_good_versions()
                    if (
                        url_request.ok
                        and '"version":"%s"' % use_version in url_request.text
                    ):
                        fver = use_version
                        found_chromedriver = True
                else:
                    url_request = get_cft_latest_versions_per_milestone()
                if not force_cft and url_request.ok:
                    fver = get_cft_latest_version_from_milestone(use_version)
                    found_chromedriver = True
                    use_version = str(fver)
                    if use_version == latest_version:
                        get_latest = True
        download_url = (
            "https://chromedriver.storage.googleapis.com/"
            "%s/%s" % (use_version, file_name)
        )
        plat_arch = ""
        if cft:
            if IS_MAC:
                if (
                    IS_ARM_MAC
                    and not intel_for_uc
                ):
                    platform_code = "mac-arm64"
                    file_name = "chromedriver-mac-arm64.zip"
                else:
                    platform_code = "mac-x64"
                    file_name = "chromedriver-mac-x64.zip"
            elif IS_LINUX:
                platform_code = "linux64"
                file_name = "chromedriver-linux64.zip"
            elif IS_WINDOWS:
                if "64" in ARCH:
                    platform_code = "win64"
                    file_name = "chromedriver-win64.zip"
                else:
                    platform_code = "win32"
                    file_name = "chromedriver-win32.zip"
            plat_arch = file_name.split(".zip")[0]
            download_url = (
                "https://storage.googleapis.com/chrome-for-testing-public/"
                "%s/%s/%s" % (use_version, platform_code, file_name)
            )
        url_request = None
        if not found_chromedriver:
            url_req = requests_get(last)
            if url_req.ok:
                latest_version = url_req.text
                if use_version == latest_version:
                    get_latest = True
            url_request = requests_get(download_url)
        if found_chromedriver or url_request.ok:
            p_version = use_version
            p_version = c3 + use_version + cr
            latest_stable = get_latest_stable_chromedriver_version()
            latest_beta = get_latest_beta_chromedriver_version()
            latest_dev = get_latest_dev_chromedriver_version()
            latest_canary = get_latest_canary_chromedriver_version()
            vint = True
            int_use_ver = None
            int_latest_ver = None
            try:
                int_use_ver = int(use_version.split(".")[0])
                int_latest_ver = int(latest_stable.split(".")[0])
            except Exception:
                vint = False
            on_cft = False
            if int_latest_ver > 115:
                on_cft = True
            if cft and on_cft and use_version == latest_stable:
                p_version = p_version + " " + c2 + "(Latest Stable)" + cr + " "
            elif cft and on_cft and use_version == latest_beta:
                p_version = p_version + " " + c2 + "(Latest Beta)" + cr + " "
            elif cft and on_cft and use_version == latest_dev:
                p_version = p_version + " " + c2 + "(Latest Dev)" + cr + " "
            elif cft and on_cft and use_version == latest_canary:
                p_version = p_version + " " + c2 + "(Latest Canary)" + cr + " "
            elif not vint:
                pass
            elif vint and cft and on_cft and int_use_ver == int_latest_ver:
                p_version = p_version + " " + c2 + "(Stable)" + cr
            elif vint and cft and on_cft and int_use_ver == int_latest_ver + 1:
                p_version = p_version + " " + c2 + "(Beta)" + cr
            elif vint and cft and on_cft and int_use_ver == int_latest_ver + 2:
                p_version = p_version + " " + c2 + "(Dev / Canary)" + cr
            elif vint and cft and on_cft and int_use_ver == int_latest_ver - 1:
                p_version = p_version + " " + c6 + "(Previous Version)" + cr
            elif cft and not on_cft:
                pass
            else:
                not_latest = c5 + "(" + c4 + "Legacy Version" + c5 + ")" + cr
                p_version = p_version + " " + not_latest
            msg = c2 + "chromedriver to download" + cr
            log_d("\n*** %s = %s" % (msg, p_version))
        else:
            raise Exception("Could not find chromedriver to download!\n")
        if not get_latest:
            pass
    elif name == "chrome" or name == "cft":
        set_version = None
        found_version = None
        use_version = None
        major_version = None
        if num_args >= 4:
            set_version = sys.argv[3]
        if (
            set_version
            and set_version.split(".")[0].isnumeric()
            and int(set_version.split(".")[0]) >= 113
        ):
            major_version = set_version.split(".")[0]
        elif (
            not set_version
            or set_version.lower() == "latest"
            or set_version.lower() == "stable"
        ):
            found_version = get_latest_stable_chromedriver_version()
        elif (
            set_version and (
                set_version.lower() == "latest-1"
                or set_version.lower() == "previous"
            )
        ):
            found_version = get_latest_stable_chromedriver_version()
            major_version = str(int(found_version.split(".")[0]) - 1)
            found_version = None
        elif (set_version and set_version.lower() == "beta"):
            found_version = get_latest_beta_chromedriver_version()
        elif (set_version and set_version.lower() == "dev"):
            found_version = get_latest_dev_chromedriver_version()
        elif (set_version and set_version.lower() == "canary"):
            found_version = get_latest_canary_chromedriver_version()
        if found_version and found_version.split(".")[0].isnumeric():
            major_version = found_version.split(".")[0]
            use_version = found_version
        if not use_version:
            use_version = get_cft_latest_version_from_milestone(major_version)
        msg = c2 + "Chrome for Testing to download" + cr
        p_version = c3 + use_version + cr
        log_d("\n*** %s = %s" % (msg, p_version))
        if IS_MAC:
            if IS_ARM_MAC:
                platform_code = "mac-arm64"
                file_name = "chrome-mac-arm64.zip"
            else:
                platform_code = "mac-x64"
                file_name = "chrome-mac-x64.zip"
        elif IS_LINUX:
            platform_code = "linux64"
            file_name = "chrome-linux64.zip"
        elif IS_WINDOWS:
            if "64" in ARCH:
                platform_code = "win64"
                file_name = "chrome-win64.zip"
            else:
                platform_code = "win32"
                file_name = "chrome-win32.zip"
        plat_arch = file_name.split(".zip")[0]
        download_url = (
            "https://storage.googleapis.com/chrome-for-testing-public/"
            "%s/%s/%s" % (use_version, platform_code, file_name)
        )
    elif name == "chrome-headless-shell" or name == "chs":
        set_version = None
        found_version = None
        use_version = None
        major_version = None
        if num_args >= 4:
            set_version = sys.argv[3]
        if (
            set_version
            and set_version.split(".")[0].isnumeric()
            and int(set_version.split(".")[0]) >= 113
        ):
            major_version = set_version.split(".")[0]
        elif (
            not set_version
            or set_version.lower() == "latest"
            or set_version.lower() == "stable"
        ):
            found_version = get_latest_stable_chromedriver_version()
        elif (
            set_version and (
                set_version.lower() == "latest-1"
                or set_version.lower() == "previous"
            )
        ):
            found_version = get_latest_stable_chromedriver_version()
            major_version = str(int(found_version.split(".")[0]) - 1)
            found_version = None
        elif (set_version and set_version.lower() == "beta"):
            found_version = get_latest_beta_chromedriver_version()
        elif (set_version and set_version.lower() == "dev"):
            found_version = get_latest_dev_chromedriver_version()
        elif (set_version and set_version.lower() == "canary"):
            found_version = get_latest_canary_chromedriver_version()
        if found_version and found_version.split(".")[0].isnumeric():
            major_version = found_version.split(".")[0]
            use_version = found_version
        if not use_version:
            use_version = get_cft_latest_version_from_milestone(major_version)
        msg = c2 + "Chrome-Headless-Shell to download" + cr
        p_version = c3 + use_version + cr
        log_d("\n*** %s = %s" % (msg, p_version))
        if IS_MAC:
            if IS_ARM_MAC:
                platform_code = "mac-arm64"
                file_name = "chrome-headless-shell-mac-arm64.zip"
            else:
                platform_code = "mac-x64"
                file_name = "chrome-headless-shell-mac-x64.zip"
        elif IS_LINUX:
            platform_code = "linux64"
            file_name = "chrome-headless-shell-linux64.zip"
        elif IS_WINDOWS:
            if "64" in ARCH:
                platform_code = "win64"
                file_name = "chrome-headless-shell-win64.zip"
            else:
                platform_code = "win32"
                file_name = "chrome-headless-shell-win32.zip"
        plat_arch = file_name.split(".zip")[0]
        download_url = (
            "https://storage.googleapis.com/chrome-for-testing-public/"
            "%s/%s/%s" % (use_version, platform_code, file_name)
        )
    elif name == "geckodriver" or name == "firefoxdriver":
        use_version = DEFAULT_GECKODRIVER_VERSION
        found_geckodriver = False
        if num_args == 4 or num_args == 5:
            if "-p" not in sys.argv[3].lower():
                use_version = sys.argv[3]
                if use_version.lower() == "latest":
                    last = (
                        "https://api.github.com/repos/"
                        "mozilla/geckodriver/releases/latest"
                    )
                    url_request = requests_get(last)
                    if url_request.ok:
                        found_geckodriver = True
                        use_version = url_request.json()["tag_name"]
                    else:
                        use_version = DEFAULT_GECKODRIVER_VERSION
            else:
                copy_to_path = True
        if num_args == 5:
            if "-p" in sys.argv[4].lower():
                copy_to_path = True
            else:
                invalid_run_command()
        if IS_MAC:
            if IS_ARM_MAC:
                file_name = "geckodriver-%s-macos-aarch64.tar.gz" % use_version
            else:
                file_name = "geckodriver-%s-macos.tar.gz" % use_version
        elif IS_LINUX:
            if "64" in ARCH:
                if "aarch64" in platform.processor():
                    file_name = (
                        "geckodriver-%s-linux-aarch64.tar.gz" % use_version
                    )
                else:
                    file_name = "geckodriver-%s-linux64.tar.gz" % use_version
            else:
                file_name = "geckodriver-%s-linux32.tar.gz" % use_version
        elif IS_WINDOWS:
            file_name = "geckodriver-%s-win64.zip" % use_version
        else:
            raise Exception(
                "Cannot determine which version of geckodriver to download!"
            )
        download_url = (
            "https://github.com/mozilla/geckodriver/"
            "releases/download/"
            "%s/%s" % (use_version, file_name)
        )
        url_request = None
        if not found_geckodriver:
            url_request = requests_get(download_url)
        if found_geckodriver or url_request.ok:
            msg = c2 + "geckodriver to download" + cr
            p_version = c3 + use_version + cr
            log_d("\n*** %s = %s" % (msg, p_version))
        else:
            raise Exception(
                "\nCould not find the specified geckodriver "
                "version to download!\n"
            )
    elif name == "edgedriver" or name == "msedgedriver":
        name = "edgedriver"
        last = (
            "https://msedgewebdriverstorage.blob.core.windows.net"
            "/edgewebdriver/LATEST_STABLE"
        )

        if (
            not override
            and (
                num_args == 3
                or (num_args == 4 and "-p" in sys.argv[3].lower())
            )
        ):
            use_version = "latest"
            major_edge_version = None
            try:
                from r_seleniumbase.core import detect_b_ver

                br_app = "edge"
                major_edge_version = (
                    detect_b_ver.get_browser_version_from_os(br_app)
                ).split(".")[0]
                if int(major_edge_version) < 80:
                    major_edge_version = None
            except Exception:
                major_edge_version = None
            if major_edge_version and major_edge_version.isnumeric():
                num_args += 1
                sys.argv.insert(3, major_edge_version)
                use_version = major_edge_version

        get_latest = False
        if num_args == 3:
            get_latest = True
        if num_args == 4 and "-p" in sys.argv[3].lower():
            get_latest = True
        if num_args == 4 or num_args == 5:
            if "-p" not in sys.argv[3].lower():
                use_version = sys.argv[3]
                if use_version.lower() == "latest":
                    use_version = DEFAULT_EDGEDRIVER_VERSION
                    get_latest = True
            else:
                copy_to_path = True
        if num_args == 5:
            if "-p" in sys.argv[4].lower():
                copy_to_path = True
            else:
                invalid_run_command()
        if get_latest:
            url_request = requests_get_with_retry(last)
            if url_request.ok:
                use_version = url_request.text.split("\r")[0].split("\n")[0]
                use_version = use_version.split(".")[0]
            else:
                use_version = DEFAULT_EDGEDRIVER_VERSION
        suffix = None
        if IS_WINDOWS and "64" in ARCH:
            file_name = "edgedriver_win64.zip"
            suffix = "WINDOWS"
        elif IS_WINDOWS:
            file_name = "edgedriver_win32.zip"
            suffix = "WINDOWS"
        elif IS_MAC:
            if IS_ARM_MAC and int(use_version.split(".")[0]) > 104:
                file_name = "edgedriver_mac64_m1.zip"
            else:
                file_name = "edgedriver_mac64.zip"
            suffix = "MACOS"
        elif IS_LINUX:
            file_name = "edgedriver_linux64.zip"
            suffix = "LINUX"
        else:
            raise Exception(
                "Cannot determine which version of EdgeDriver to download!"
            )
        if use_version.isdigit():
            edgedriver_st = "https://msedgedriver.azureedge.net/LATEST_RELEASE"
            use_version = "%s_%s_%s" % (edgedriver_st, use_version, suffix)
            url_request = requests_get_with_retry(use_version)
            if url_request.ok:
                use_version = url_request.text.split("\r")[0].split("\n")[0]
                if (
                    int(use_version.split(".")[0]) == 115
                    and use_version.startswith("115.0")
                    and use_version != "115.0.1901.183"
                ):
                    use_version = "115.0.1901.183"
        download_url = "https://msedgedriver.azureedge.net/%s/%s" % (
            use_version,
            file_name,
        )
        if not get_latest and not use_version == DEFAULT_EDGEDRIVER_VERSION:
            url_request = requests_get_with_retry(download_url)
            if not url_request.ok:
                raise Exception(
                    "Could not find version [%s] of EdgeDriver!" % use_version
                )
        msg = c2 + "edgedriver to download" + cr
        p_version = c3 + use_version + cr
        log_d("\n*** %s = %s" % (msg, p_version))
    elif name == "iedriver":
        full_version = "4.14.0"
        use_version = full_version
        if IS_WINDOWS and "64" in ARCH:
            file_name = "IEDriverServer_x64_%s.zip" % full_version
        elif IS_WINDOWS:
            file_name = "IEDriverServer_Win32_%s.zip" % full_version
        else:
            raise Exception(
                "Sorry! IEDriver is only for "
                "Windows-based systems!"
            )
        download_url = (
            "https://github.com/seleniumHQ/r_selenium/"
            "releases/download/r_selenium-"
            "%s/%s" % (full_version, file_name)
        )
        headless_ie_version = "v1.4"
        headless_ie_file_name = "headless-r_selenium-for-win-v1-4.zip"
        headless_ie_url = (
            "https://github.com/kybu/headless-r_selenium-for-win/"
            "releases/download/"
            "%s/%s" % (headless_ie_version, headless_ie_file_name)
        )
        url_request = requests_get_with_retry(headless_ie_url)
        if url_request.ok:
            headless_ie_exists = True
            msg = c2 + "HeadlessIEDriver to download" + cr
            p_version = c3 + headless_ie_version + cr
            log_d("\n*** %s = %s" % (msg, p_version))
    else:
        invalid_run_command()

    if file_name is None or download_url is None:
        invalid_run_command()

    file_path = os.path.join(downloads_folder, file_name)
    if not os.path.exists(downloads_folder):
        os.makedirs(downloads_folder)

    driver_name = None  # The name of the driver executable
    driver_contents = []  # The contents of the driver zip file

    if headless_ie_exists:
        headless_ie_file_path = os.path.join(
            downloads_folder, headless_ie_file_name
        )
        log_d(
            "\nDownloading %s from:\n%s ..."
            % (headless_ie_file_name, headless_ie_url)
        )
        remote_file = requests_get_with_retry(headless_ie_url)
        with open(headless_ie_file_path, "wb") as file:
            file.write(remote_file.content)
        log_d("%sDownload Complete!%s\n" % (c1, cr))
        zip_file_path = headless_ie_file_path
        zip_ref = zipfile.ZipFile(zip_file_path, "r")
        contents = zip_ref.namelist()
        h_ie_fn = headless_ie_file_name.split(".zip")[0]
        expected_contents = [
            "%s/" % h_ie_fn,
            "%s/ruby_example/" % h_ie_fn,
            "%s/ruby_example/Gemfile" % h_ie_fn,
            "%s/ruby_example/Gemfile.lock" % h_ie_fn,
            "%s/ruby_example/ruby_example.rb" % h_ie_fn,
            "%s/desktop_utils.exe" % h_ie_fn,
            "%s/headless_ie_selenium.exe" % h_ie_fn,
            "%s/README.md" % h_ie_fn,
        ]
        if len(contents) > 8:
            raise Exception("Unexpected content in HeadlessIEDriver Zip file!")
        for content in contents:
            if content not in expected_contents:
                raise Exception(
                    "Expected file [%s] missing from [%s]"
                    % (content, expected_contents)
                )
        # Zip file is valid. Proceed.
        driver_path = None
        driver_file = None
        filename = None
        for f_name in contents:
            # Remove existing version if exists
            str_name = str(f_name)
            new_file = os.path.join(downloads_folder, str_name)
            if str_name == "%s/headless_ie_selenium.exe" % h_ie_fn:
                driver_file = str_name
                driver_path = new_file
                filename = "headless_ie_selenium.exe"
                if os.path.exists(new_file):
                    os.remove(new_file)
        if not driver_file or not driver_path or not filename:
            raise Exception("headless_ie_selenium.exe missing from Zip file!")
        log_d("Extracting %s from %s ..." % (filename, headless_ie_file_name))
        zip_ref.extractall(downloads_folder)
        zip_ref.close()
        os.remove(zip_file_path)
        shutil.copy3(driver_path, os.path.join(downloads_folder, filename))
        log_d("%sUnzip Complete!%s\n" % (c2, cr))
        to_remove = [
            "%s/%s/ruby_example/Gemfile" % (downloads_folder, h_ie_fn),
            "%s/%s/ruby_example/Gemfile.lock" % (downloads_folder, h_ie_fn),
            "%s/%s/ruby_example/ruby_example.rb" % (downloads_folder, h_ie_fn),
            "%s/%s/desktop_utils.exe" % (downloads_folder, h_ie_fn),
            "%s/%s/headless_ie_selenium.exe" % (downloads_folder, h_ie_fn),
            "%s/%s/README.md" % (downloads_folder, h_ie_fn),
        ]
        for file_to_remove in to_remove:
            if os.path.exists(file_to_remove):
                os.remove(file_to_remove)
        if os.path.exists("%s/%s/ruby_example/" % (downloads_folder, h_ie_fn)):
            # Only works if the directory is empty
            os.rmdir("%s/%s/ruby_example/" % (downloads_folder, h_ie_fn))
        if os.path.exists(os.path.join(downloads_folder, h_ie_fn)):
            # Only works if the directory is empty
            os.rmdir(os.path.join(downloads_folder, h_ie_fn))
        driver_path = os.path.join(downloads_folder, filename)
        log_d(
            "The file [%s] was saved to:\n%s%s%s\n"
            % (filename, c3, driver_path, cr)
        )
        log_d("Making [%s %s] executable ..." % (driver_file, use_version))
        make_executable(driver_path)
        log_d(
            "%s[%s %s] is now ready for use!%s"
            % (c1, driver_file, use_version, cr)
        )

    log_d("\nDownloading %s from:\n%s ..." % (file_name, download_url))
    remote_file = requests_get_with_retry(download_url)
    with open(file_path, "wb") as file:
        file.write(remote_file.content)
    log_d("%sDownload Complete!%s\n" % (c1, cr))

    if file_name.endswith(".zip"):
        zip_file_path = file_path
        zip_ref = zipfile.ZipFile(zip_file_path, "r")
        contents = zip_ref.namelist()
        if (
            len(contents) >= 1
            and name in ["chromedriver", "uc_driver", "geckodriver"]
        ):
            for f_name in contents:
                if (
                    (name == "chromedriver" or name == "uc_driver")
                    and (
                        f_name.split("/")[-1] == "chromedriver"
                        or f_name.split("/")[-1] == "chromedriver.exe"
                    )
                ):
                    driver_name = f_name.split("/")[-1]
                    driver_contents = [driver_name]
                # Remove existing version if exists
                new_file = os.path.join(downloads_folder, str(f_name))
                if name == "uc_driver":
                    if new_file.endswith("drivers/chromedriver"):
                        new_file = new_file.replace(
                            "drivers/chromedriver", "drivers/uc_driver"
                        )
                    elif new_file.endswith("drivers/chromedriver.exe"):
                        new_file = new_file.replace(
                            "drivers/chromedriver.exe", "drivers/uc_driver.exe"
                        )
                    elif "drivers/%s/chromedriver" % plat_arch in new_file:
                        new_file = new_file.replace(
                            "drivers/%s/chromedriver" % plat_arch,
                            "drivers/%s/uc_driver" % plat_arch
                        )
                    elif "drivers/%s/chromedriver.exe" % plat_arch in new_file:
                        new_file = new_file.replace(
                            "drivers/%s/chromedriver.exe" % plat_arch,
                            "drivers/%s/uc_driver.exe" % plat_arch
                        )
                if "Driver" in new_file or "driver" in new_file:
                    if os.path.exists(new_file):
                        os.remove(new_file)  # Technically the old file now
            if driver_contents:
                contents = driver_contents
            log_d("Extracting %s from %s ..." % (contents, file_name))
            if name == "uc_driver":
                f_name = "uc_driver"
                new_file = os.path.join(downloads_folder, f_name)
                if os.path.exists(new_file):
                    os.remove(new_file)
                zipinfos = zip_ref.infolist()
                for zipinfo in zipinfos:
                    if zipinfo.filename.split("/")[-1] == "chromedriver":
                        zipinfo.filename = "uc_driver"
                        zip_ref.extract(zipinfo, downloads_folder)
                    elif zipinfo.filename.split("/")[-1] == "chromedriver.exe":
                        zipinfo.filename = "uc_driver.exe"
                        zip_ref.extract(zipinfo, downloads_folder)
                contents = zip_ref.namelist()
                if driver_contents:
                    contents = driver_contents
            elif name == "chromedriver" or name == "uc_driver":
                zipinfos = zip_ref.infolist()
                for zipinfo in zipinfos:
                    if zipinfo.filename.split("/")[-1] == "chromedriver":
                        zipinfo.filename = "chromedriver"
                    elif zipinfo.filename.split("/")[-1] == (
                        "chromedriver.exe"
                    ):
                        zipinfo.filename = "chromedriver.exe"
                    if (
                        zipinfo.filename.split("/")[-1] == "chromedriver"
                        or zipinfo.filename.split("/")[-1] == (
                            "chromedriver.exe"
                        )
                    ):
                        zip_ref.extract(zipinfo, downloads_folder)
                contents = zip_ref.namelist()
                if driver_contents:
                    contents = driver_contents
            else:
                zip_ref.extractall(downloads_folder)
            zip_ref.close()
            os.remove(zip_file_path)
            log_d("%sUnzip Complete!%s\n" % (c2, cr))
            for f_name in contents:
                if name == "uc_driver":
                    if IS_WINDOWS:
                        f_name = "uc_driver.exe"
                    else:
                        f_name = "uc_driver"
                new_file = os.path.join(downloads_folder, str(f_name))
                pr_file = c3 + new_file + cr
                d_folder = os.sep.join(pr_file.split(os.sep)[:-1]) + os.sep
                d_file = pr_file.split(os.sep)[-1]
                d_ff = c3 + d_folder + cr + "\n" + c3 + d_file + cr
                log_d("The file [%s] was saved to:\n%s\n" % (f_name, d_ff))
                log_d("Making [%s %s] executable ..." % (f_name, use_version))
                make_executable(new_file)
                log_d(
                    "%s[%s %s] is now ready for use!%s" %
                    (c1, f_name, use_version, cr)
                )
                if copy_to_path and os.path.exists(LOCAL_PATH):
                    path_file = LOCAL_PATH + f_name
                    shutil.copy2(new_file, path_file)
                    make_executable(path_file)
                    log_d("Also copied to: %s%s%s" % (c3, path_file, cr))
            log_d("")
        elif (
            name == "edgedriver"
            or name == "msedgedriver"
            or name == "iedriver"
        ):
            if IS_MAC or IS_LINUX:
                # Mac / Linux
                expected_contents = [
                    "Driver_Notes/",
                    "Driver_Notes/EULA",
                    "Driver_Notes/LICENSE",
                    "Driver_Notes/credits.html",
                    "msedgedriver",
                    "libc++.dylib",
                ]
            else:
                # Windows
                expected_contents = [
                    "Driver_Notes/",
                    "Driver_Notes/credits.html",
                    "Driver_Notes/EULA",
                    "Driver_Notes/LICENSE",
                    "msedgedriver.exe",
                ]
            if name == "iedriver":
                expected_contents = ["IEDriverServer.exe"]
            if len(contents) > 5:
                raise Exception("Unexpected content in EdgeDriver Zip file!")
            for content in contents:
                if content not in expected_contents:
                    raise Exception(
                        "Expected file [%s] missing from [%s]"
                        % (content, expected_contents)
                    )
            # Zip file is valid. Proceed.
            driver_path = None
            driver_file = None
            for f_name in contents:
                # Remove existing version if exists
                str_name = str(f_name)
                new_file = os.path.join(downloads_folder, str_name)
                if (
                    ((IS_MAC or IS_LINUX) and str_name == "msedgedriver")
                    or (
                        str_name == "msedgedriver.exe"
                        or str_name == "IEDriverServer.exe"
                    )
                ):
                    driver_file = str_name
                    driver_path = new_file
                    if os.path.exists(new_file):
                        os.remove(new_file)
            if not driver_file or not driver_path:
                if str_name == "IEDriverServer.exe":
                    raise Exception("IEDriverServer missing from Zip file!")
                raise Exception("msedgedriver missing from Zip file!")
            log_d("Extracting %s from %s ..." % (contents, file_name))
            zip_ref.extractall(downloads_folder)
            zip_ref.close()
            os.remove(zip_file_path)
            log_d("%sUnzip Complete!%s\n" % (c2, cr))
            to_remove = [
                "%s/Driver_Notes/credits.html" % downloads_folder,
                "%s/Driver_Notes/EULA" % downloads_folder,
                "%s/Driver_Notes/LICENSE" % downloads_folder,
            ]
            for file_to_remove in to_remove:
                if os.path.exists(file_to_remove):
                    os.remove(file_to_remove)
            if os.path.exists(os.path.join(downloads_folder, "Driver_Notes/")):
                # Only works if the directory is empty
                os.rmdir(os.path.join(downloads_folder, "Driver_Notes/"))
            driver_base = os.sep.join(driver_path.split(os.sep)[:-1])
            driver_file = driver_path.split(os.sep)[-1]
            pr_driver_base = c3 + driver_base + cr
            pr_sep = c3 + os.sep + cr
            pr_driver_file = c3 + driver_file + cr
            log_d(
                "The file [%s] was saved to:\n%s%s\n%s\n"
                % (driver_file, pr_driver_base, pr_sep, pr_driver_file)
            )
            log_d("Making [%s %s] executable ..." % (driver_file, use_version))
            make_executable(driver_path)
            log_d(
                "%s[%s %s] is now ready for use!%s"
                % (c1, driver_file, use_version, cr)
            )
            if copy_to_path and os.path.exists(LOCAL_PATH):
                path_file = LOCAL_PATH + f_name
                shutil.copy2(new_file, path_file)
                make_executable(path_file)
                log_d("Also copied to: %s%s%s" % (c3, path_file, cr))
            log_d("")
        elif name == "chrome" or name == "cft":
            # Zip file is valid. Proceed.
            driver_path = None
            driver_file = None
            base_path = os.sep.join(zip_file_path.split(os.sep)[:-1])
            folder_name = contents[0].split("/")[0]
            folder_path = os.path.join(base_path, folder_name)
            if IS_MAC or IS_LINUX:
                if (
                    "chrome-" in folder_path
                    and "drivers" in folder_path
                    and os.path.exists(folder_path)
                ):
                    shutil.rmtree(folder_path)
                subprocess.run(
                    ["unzip", zip_file_path, "-d", downloads_folder]
                )
            elif IS_WINDOWS:
                subprocess.run(
                    [
                        "powershell",
                        "Expand-Archive",
                        "-Path",
                        zip_file_path,
                        "-DestinationPath",
                        downloads_folder,
                        "-Force",
                    ]
                )
            else:
                zip_ref.extractall(downloads_folder)
                zip_ref.close()
            with suppress(Exception):
                os.remove(zip_file_path)
            log_d("%sUnzip Complete!%s\n" % (c2, cr))
            pr_base_path = c3 + base_path + cr
            pr_sep = c3 + os.sep + cr
            pr_folder_name = c3 + folder_name + cr
            log_d(
                "Chrome for Testing was saved inside:\n%s%s\n%s\n"
                % (pr_base_path, pr_sep, pr_folder_name)
            )
        elif name == "chrome-headless-shell" or name == "chs":
            # Zip file is valid. Proceed.
            driver_path = None
            driver_file = None
            base_path = os.sep.join(zip_file_path.split(os.sep)[:-1])
            folder_name = contents[0].split("/")[0]
            folder_path = os.path.join(base_path, folder_name)
            if IS_MAC or IS_LINUX:
                if (
                    "chrome-headless-shell-" in folder_path
                    and "drivers" in folder_path
                    and os.path.exists(folder_path)
                ):
                    shutil.rmtree(folder_path)
                subprocess.run(
                    ["unzip", zip_file_path, "-d", downloads_folder]
                )
            elif IS_WINDOWS:
                subprocess.run(
                    [
                        "powershell",
                        "Expand-Archive",
                        "-Path",
                        zip_file_path,
                        "-DestinationPath",
                        downloads_folder,
                        "-Force",
                    ]
                )
            else:
                zip_ref.extractall(downloads_folder)
                zip_ref.close()
            with suppress(Exception):
                os.remove(zip_file_path)
            log_d("%sUnzip Complete!%s\n" % (c2, cr))
            pr_base_path = c3 + base_path + cr
            pr_sep = c3 + os.sep + cr
            pr_folder_name = c3 + folder_name + cr
            log_d(
                "Chrome-Headless-Shell was saved inside:\n%s%s\n%s\n"
                % (pr_base_path, pr_sep, pr_folder_name)
            )
        elif len(contents) == 0:
            raise Exception("Zip file %s is empty!" % zip_file_path)
        else:
            raise Exception("Expecting only one file in %s!" % zip_file_path)
    elif file_name.endswith(".tar.gz"):
        tar_file_path = file_path
        tar = tarfile.open(file_path)
        contents = tar.getnames()
        if len(contents) == 1:
            for f_name in contents:
                # Remove existing version if exists
                new_file = os.path.join(downloads_folder, str(f_name))
                if "Driver" in new_file or "driver" in new_file:
                    if os.path.exists(new_file):
                        os.remove(new_file)  # Technically the old file now
            log_d("Extracting %s from %s ..." % (contents, file_name))
            if sys.version_info < (3, 12):
                tar.extractall(downloads_folder)
            else:
                tar.extractall(downloads_folder, filter="fully_trusted")
            tar.close()
            os.remove(tar_file_path)
            log_d("%sUnzip Complete!%s\n" % (c2, cr))
            for f_name in contents:
                new_file = os.path.join(downloads_folder, str(f_name))
                pr_file = c3 + new_file + cr
                log_d("The file [%s] was saved to:\n%s\n" % (f_name, pr_file))
                log_d("Making [%s %s] executable ..." % (f_name, use_version))
                make_executable(new_file)
                log_d(
                    "%s[%s %s] is now ready for use!%s"
                    % (c1, f_name, use_version, cr)
                )
                if copy_to_path and os.path.exists(LOCAL_PATH):
                    path_file = LOCAL_PATH + f_name
                    shutil.copy2(new_file, path_file)
                    make_executable(path_file)
                    log_d("Also copied to: %s%s%s" % (c3, path_file, cr))
            log_d("")
        elif len(contents) == 0:
            raise Exception("Tar file %s is empty!" % tar_file_path)
        else:
            raise Exception("Expecting only one file in %s!" % tar_file_path)
    else:
        # Not a .zip file or a .tar.gz file. Just a direct download.
        if "Driver" in file_name or "driver" in file_name:
            log_d("Making [%s] executable ..." % file_name)
            make_executable(file_path)
            log_d("%s[%s] is now ready for use!%s" % (c1, file_name, cr))
            log_d("Location of [%s]:\n%s\n" % (file_name, file_path))


if __name__ == "__main__":
    main()
