from _typeshed import Incomplete
from collections.abc import Mapping, MutableMapping, Sequence
from re import Pattern
from typing import Any, Final, Literal, TypeAlias, TypedDict, overload, type_check_only
from typing_extensions import Required, deprecated

import requests
from requests._types import AuthType
from requests.models import Request, Response

LAUNCHER_SSH: Final[str]
LAUNCHER_COMMAND: Final[str]
LAUNCHER_JNLP: Final[str]
LAUNCHER_WINDOWS_SERVICE: Final[str]
DEFAULT_HEADERS: Final[dict[str, str]]
DEFAULT_TIMEOUT: Final[float]
DEFAULT_RETRIES: Final = 0
INFO: Final[str]
PLUGIN_INFO: Final[str]
CRUMB_URL: Final[str]
WHOAMI_URL: Final[str]
JOBS_QUERY: Final[str]
JOBS_QUERY_TREE: Final[str]
JOB_INFO: Final[str]
JOB_NAME: Final[str]
ALL_BUILDS: Final[str]
Q_INFO: Final[str]
Q_ITEM: Final[str]
CANCEL_QUEUE: Final[str]
CREATE_JOB: Final[str]
CONFIG_JOB: Final[str]
DELETE_JOB: Final[str]
ENABLE_JOB: Final[str]
DISABLE_JOB: Final[str]
CHECK_JENKINSFILE_SYNTAX: Final[str]
SET_JOB_BUILD_NUMBER: Final[str]
COPY_JOB: Final[str]
RENAME_JOB: Final[str]
BUILD_JOB: Final[str]
STOP_BUILD: Final[str]
BUILD_WITH_PARAMS_JOB: Final[str]
BUILD_INFO: Final[str]
BUILD_CONSOLE_OUTPUT: Final[str]
BUILD_ENV_VARS: Final[str]
BUILD_TEST_REPORT: Final[str]
BUILD_ARTIFACT: Final[str]
BUILD_STAGES: Final[str]
DELETE_BUILD: Final[str]
WIPEOUT_JOB_WORKSPACE: Final[str]
NODE_LIST: Final[str]
CREATE_NODE: Final[str]
DELETE_NODE: Final[str]
NODE_INFO: Final[str]
NODE_TYPE: Final[str]
TOGGLE_OFFLINE: Final[str]
CONFIG_NODE: Final[str]
VIEW_NAME: Final[str]
VIEW_JOBS: Final[str]
CREATE_VIEW: Final[str]
CONFIG_VIEW: Final[str]
DELETE_VIEW: Final[str]
SCRIPT_TEXT: Final[str]
NODE_SCRIPT_TEXT: Final[str]
PROMOTION_NAME: Final[str]
PROMOTION_INFO: Final[str]
DELETE_PROMOTION: Final[str]
CREATE_PROMOTION: Final[str]
CONFIG_PROMOTION: Final[str]
LIST_CREDENTIALS: Final[str]
CREATE_CREDENTIAL: Final[str]
CONFIG_CREDENTIAL: Final[str]
CREDENTIAL_INFO: Final[str]
QUIET_DOWN: Final[str]
EMPTY_CONFIG_XML: Final[str]
EMPTY_FOLDER_XML: Final[str]
RECONFIG_XML: Final[str]
EMPTY_VIEW_CONFIG_XML: Final[str]
EMPTY_PROMO_CONFIG_XML: Final[str]
PROMO_RECONFIG_XML: Final[str]

class JenkinsException(Exception): ...
class NotFoundException(JenkinsException): ...
class EmptyResponseException(JenkinsException): ...
class BadHTTPException(JenkinsException): ...
class TimeoutException(JenkinsException): ...

class WrappedSession(requests.Session):
    # merge_environment_settings wraps requests.Session.merge_environment_settings
    # w/o changing the type signature
    ...

_JSONValue: TypeAlias = Any  # too many possibilities to express
_JSON: TypeAlias = dict[str, _JSONValue]

@type_check_only
class _Job(TypedDict, total=False):
    _class: Required[str]
    url: Required[str]
    color: str
    name: Required[str]
    fullname: Required[str]
    jobs: list[_Job]

class Jenkins:
    server: str
    auth: AuthType | None
    crumb: Mapping[str, Incomplete] | bool | Incomplete
    timeout: int
    def __init__(
        self, url: str, username: str | None = None, password: str | None = None, timeout: int = ..., retries: int = 0
    ) -> None: ...
    def maybe_add_crumb(self, req: Request) -> None: ...
    def get_job_info(self, name: str, depth: int = 0, fetch_all_builds: bool = False) -> _JSON: ...
    def get_job_info_regex(
        self, pattern: str | Pattern[str], depth: int = 0, folder_depth: int = 0, folder_depth_per_request: int = 10
    ) -> list[_JSON]: ...
    def get_job_name(self, name: str) -> str | None: ...
    def debug_job_info(self, job_name: str) -> None: ...
    def jenkins_open(self, req: Request, add_crumb: bool = True, resolve_auth: bool = True) -> str: ...
    def jenkins_open_stream(self, req: Request, add_crumb: bool = True, resolve_auth: bool = True) -> Response: ...
    def jenkins_request(
        self, req: Request, add_crumb: bool = True, resolve_auth: bool = True, stream: bool | None = None
    ) -> Response: ...
    def get_queue_item(self, number: int, depth: int = 0) -> _JSON: ...
    def get_build_info(self, name: str, number: int, depth: int = 0) -> _JSON: ...
    def get_build_env_vars(self, name: str, number: int, depth: int = 0) -> _JSON | None: ...
    def get_build_test_report(self, name: str, number: int, depth: int = 0, tree: str | None = None) -> _JSON | None: ...
    def get_build_artifact(self, name: str, number: int, artifact: str) -> _JSON: ...
    def get_build_artifact_as_bytes(self, name: str, number: int, artifact: str) -> bytes: ...
    def get_build_stages(self, name: str, number: int) -> _JSON: ...
    def get_queue_info(self) -> _JSON: ...
    def cancel_queue(self, id: int) -> None: ...
    def get_info(self, item: str = "", query: str | None = None) -> _JSON: ...
    def get_whoami(self, depth: int = 0) -> _JSON: ...
    def get_version(self) -> str: ...
    @deprecated("Deprecated since 0.4.9. Use `get_plugins` instead.")
    def get_plugins_info(self, depth: int = 2) -> _JSON: ...
    def get_plugin_info(self, name: str, depth: int = 2) -> _JSON: ...
    def get_plugins(self, depth: int = 2) -> _JSON: ...
    def get_jobs(self, folder_depth: int = 0, folder_depth_per_request: int = 10, view_name: str | None = None) -> list[_Job]: ...
    def get_all_jobs(self, folder_depth: int | None = None, folder_depth_per_request: int = 10) -> list[_Job]: ...
    def copy_job(self, from_name: str, to_name: str) -> None: ...
    def rename_job(self, from_name: str, to_name: str) -> None: ...
    def delete_job(self, name: str) -> None: ...
    def enable_job(self, name: str) -> None: ...
    def disable_job(self, name: str) -> None: ...
    def set_next_build_number(self, name: str, number: int) -> None: ...
    def job_exists(self, name: str) -> bool: ...
    def jobs_count(self) -> int: ...
    def assert_job_exists(self, name: str, exception_message: str = "job[%s] does not exist") -> None: ...
    def create_folder(self, folder_name: str, ignore_failures: bool = False) -> None: ...
    def upsert_job(self, name: str, config_xml: str) -> None: ...
    def check_jenkinsfile_syntax(self, jenkinsfile: str) -> list[str]: ...
    def create_job(self, name: str, config_xml: str) -> None: ...
    def get_job_config(self, name: str) -> str: ...
    def reconfig_job(self, name: str, config_xml: str) -> None: ...

    @overload
    def build_job_url(
        self,
        name: str,
        parameters: Mapping[str, Incomplete] | Sequence[tuple[str, Incomplete]] | None = None,
        token: Literal[""] | None = None,
    ) -> str: ...
    @overload
    def build_job_url(
        self, name: str, parameters: dict[str, Incomplete] | list[tuple[str, Incomplete]] | None, token: str
    ) -> str: ...
    @overload
    def build_job_url(
        self, name: str, parameters: dict[str, Incomplete] | list[tuple[str, Incomplete]] | None = None, *, token: str
    ) -> str: ...

    @overload
    def build_job(
        self,
        name: str,
        parameters: Mapping[str, Incomplete] | Sequence[tuple[str, Incomplete]] | None = None,
        token: Literal[""] | None = None,
    ) -> int: ...
    @overload
    def build_job(
        self, name: str, parameters: dict[str, Incomplete] | list[tuple[str, Incomplete]] | None, token: str
    ) -> int: ...
    @overload
    def build_job(
        self, name: str, parameters: dict[str, Incomplete] | list[tuple[str, Incomplete]] | None = None, *, token: str
    ) -> int: ...

    def run_script(self, script: str, node: str | None = None) -> str: ...
    def install_plugin(self, name: str, include_dependencies: bool = True) -> bool: ...
    def stop_build(self, name: str, number: int) -> None: ...
    def delete_build(self, name: str, number: int) -> None: ...
    def wipeout_job_workspace(self, name: str) -> None: ...
    def get_running_builds(self) -> list[_JSON]: ...
    def get_nodes_with_info(self, depth: int = 0) -> list[_JSON]: ...
    def get_nodes(self, depth: int = 0) -> list[_JSON]: ...
    def get_node_info(self, name: str, depth: int = 0) -> _JSON: ...
    def node_exists(self, name: str) -> bool: ...
    def assert_node_exists(self, name: str, exception_message: str = "node[%s] does not exist") -> None: ...
    def delete_node(self, name: str) -> None: ...
    def disable_node(self, name: str, msg: str = "") -> None: ...
    def enable_node(self, name: str) -> None: ...
    def create_node(
        self,
        name: str,
        numExecutors: int = 2,
        nodeDescription: str | None = None,
        remoteFS: str = "/var/lib/jenkins",
        labels: str | None = None,
        exclusive: bool = False,
        launcher: str = "hudson.slaves.CommandLauncher",
        launcher_params: MutableMapping[str, Incomplete] = {},
    ) -> None: ...
    def get_node_config(self, name: str) -> str: ...
    def reconfig_node(self, name: str, config_xml: str) -> None: ...
    def get_build_console_output(self, name: str, number: int) -> str: ...
    def get_view_name(self, name: str) -> str | None: ...
    def assert_view_exists(self, name: str, exception_message: str = "view[%s] does not exist") -> None: ...
    def view_exists(self, name: str) -> bool: ...
    def get_views(self) -> list[_JSON]: ...
    def delete_view(self, name: str) -> None: ...
    def create_view(self, name: str, config_xml: str) -> None: ...
    def reconfig_view(self, name: str, config_xml: str) -> None: ...
    def get_view_config(self, name: str) -> str: ...
    def get_promotion_name(self, name: str, job_name: str) -> str | None: ...
    def assert_promotion_exists(
        self, name: str, job_name: str, exception_message: str = "promotion[%s] does not exist for job[%s]"
    ) -> None: ...
    def promotion_exists(self, name: str, job_name: str) -> bool: ...
    def get_promotions_info(self, job_name: str, depth: int = 0) -> _JSON: ...
    def get_promotions(self, job_name: str) -> list[_JSON]: ...
    def delete_promotion(self, name: str, job_name: str) -> None: ...
    def create_promotion(self, name: str, job_name: str, config_xml: str) -> None: ...
    def reconfig_promotion(self, name: str, job_name: str, config_xml: str) -> None: ...
    def get_promotion_config(self, name: str, job_name: str) -> str: ...
    def assert_folder(self, name: str, exception_message: str = "job[%s] is not a folder") -> None: ...
    def is_folder(self, name: str) -> bool: ...
    def assert_credential_exists(
        self,
        name: str,
        folder_name: str,
        domain_name: str = "_",
        exception_message: str = "credential[%s] does not exist in the domain[%s] of [%s]",  # noqa: Y053
    ) -> None: ...
    def credential_exists(self, name: str, folder_name: str, domain_name: str = "_") -> bool: ...
    def get_credential_info(self, name: str, folder_name: str, domain_name: str = "_") -> _JSON: ...
    def get_credential_config(self, name: str, folder_name: str, domain_name: str = "_") -> str: ...
    def create_credential(self, folder_name: str, config_xml: str, domain_name: str = "_") -> None: ...
    def delete_credential(self, name: str, folder_name: str, domain_name: str = "_") -> None: ...
    def reconfig_credential(self, folder_name: str, config_xml: str, domain_name: str = "_") -> None: ...
    def list_credentials(self, folder_name: str, domain_name: str = "_") -> list[Incomplete]: ...
    def quiet_down(self) -> None: ...
    def wait_for_normal_op(self, timeout: int) -> bool: ...
