from abc import ABC
import typing_extensions

from experimaestro.core.types import ObjectType
import experimaestro
import io
from experimaestro.launchers import Launcher
from experimaestro.scheduler.base import Job

from experimaestro.scheduler.workspace import RunMode
from .context import (
    SerializationContext as SerializationContext,
    SerializedPath as SerializedPath,
    SerializedPathLoader as SerializedPathLoader,
)
from _typeshed import Incomplete
from collections.abc import Generator
from experimaestro.core.types import (
    DeprecatedAttribute as DeprecatedAttribute,
    ObjectType as ObjectType,
)
from experimaestro.utils import logger as logger
from functools import cached_property as cached_property
from pathlib import Path
from typing import (
    Any,
    Callable,
    ClassVar,
    Dict,
    Generic,
    List,
    Optional,
    Set,
    Type,
    TypeVar,
    Union,
    overload,
)
from typing_extensions import Self

TConfig = TypeVar("TConfig", bound="Config")

class Identifier:
    main: Incomplete
    sub: Incomplete
    def __init__(self, main: bytes, sub: Optional[bytes] = ...) -> None: ...
    def all(self): ...
    def state_dict(self): ...
    @staticmethod
    def from_state_dict(data: Union[Dict[str, str], str]): ...

def is_ignored(value): ...
def remove_meta(value): ...

class ObjectStore: ...

class HashComputer:
    OBJECT_ID: bytes
    INT_ID: bytes
    FLOAT_ID: bytes
    STR_ID: bytes
    PATH_ID: bytes
    NAME_ID: bytes
    NONE_ID: bytes
    LIST_ID: bytes
    TASK_ID: bytes
    DICT_ID: bytes
    ENUM_ID: bytes
    def __init__(self) -> None: ...
    def identifier(self) -> Identifier: ...
    def update(self, value, myself: bool = ...): ...

def updatedependencies(
    dependencies, value: Config, path: List[str], taskids: Set[int]
): ...

class TaggedValue:
    value: Incomplete
    def __init__(self, value) -> None: ...

def add_to_path(p) -> Generator[None, None, None]: ...

class ConfigWalkContext:
    @property
    def path(self) -> None: ...
    def __init__(self) -> None: ...
    @property
    def task(self) -> None: ...
    def currentpath(self) -> Path: ...
    def push(self, key: str): ...

NOT_SET: Incomplete

class ConfigProcessing:
    recurse_task: Incomplete
    visited: Incomplete
    def __init__(self, recurse_task: bool = ...) -> None: ...
    def preprocess(self, config: Config): ...
    def postprocess(self, config: Config, values: Dict[str, Any]): ...
    def list(self, i: int): ...
    def map(self, k: str): ...
    def __call__(self, x): ...

class ConfigWalk(ConfigProcessing):
    context: Incomplete
    def __init__(self, context: ConfigWalkContext) -> None: ...
    def list(self, i: int): ...
    def map(self, k: str): ...

def getqualattr(module, qualname): ...

class ConfigInformation:
    LOADING: bool
    pyobject: Config
    xpmtype: ObjectType
    values: Dict[str, Any]
    job: Job
    dependencies: Incomplete
    def __init__(self, pyobject: TypeConfig) -> None: ...
    def set_meta(self, value: Optional[bool]): ...
    @property
    def meta(self): ...
    def get(self, name): ...
    def set(self, k, v, bypass: bool = ...) -> None: ...
    def addtag(self, name, value) -> None: ...
    def xpmvalues(self, generated: bool = ...) -> Generator[Incomplete, None, None]: ...
    def tags(self): ...
    def validate(self) -> None: ...
    def seal(self, context: ConfigWalkContext): ...
    @property
    def identifier(self) -> Identifier: ...
    def dependency(self): ...
    def updatedependencies(
        self,
        dependencies: Set["experimaestro.dependencies.Dependency"],
        path: List[str],
        taskids: Set[int],
    ): ...
    def submit(
        self,
        workspace,
        launcher,
        run_mode: RunMode = ...,
        init_tasks: List["LightweightTask"] = [],
    ) -> Task: ...
    def outputjson(self, out: io.TextIOBase, context: SerializationContext): ...
    def __json__(self): ...
    def serialize(self, save_directory: Path): ...
    @staticmethod
    def deserialize(
        path: Union[str, Path, SerializedPathLoader], as_instance: bool = ...
    ) -> Config: ...
    @overload
    @staticmethod
    def fromParameters(
        definitions: List[Dict],
        as_instance: bool = ...,
        save_directory: Optional[Path] = ...,
    ) -> TypeConfig: ...
    @overload
    @staticmethod
    def fromParameters(
        definitions: List[Dict],
        as_instance: bool = ...,
        save_directory: Optional[Path] = ...,
    ) -> Config: ...

    class FromPython(ConfigWalk):
        objects: Incomplete
        def __init__(self, context: ConfigWalkContext) -> None: ...
        def preprocess(self, config: Config): ...
        def postprocess(self, config: Config, values: Dict[str, Any]): ...

    def fromConfig(self, context: ConfigWalkContext): ...
    def add_dependencies(self, *dependencies) -> None: ...

def clone(v): ...
def cache(fn, name: str): ...

class TypeConfig:
    __xpmtype__: ObjectType
    __xpm__: Incomplete
    def __init__(self, **kwargs) -> None: ...
    def tag(self, name, value): ...
    def __eq__(self, other): ...
    def __arguments__(self): ...
    def tags(self): ...
    def add_dependencies(self, *dependencies): ...
    def instance(
        self, context: ConfigWalkContext = ..., *, objects: ObjectStore = None
    ) -> Any: ...
    def submit(
        self,
        *,
        workspace: Incomplete | None = ...,
        launcher: Incomplete | None = ...,
        run_mode: RunMode = ...
    ): ...
    def stdout(self): ...
    def stderr(self): ...
    @property
    def job(self): ...
    @property
    def jobpath(self): ...
    def copy(self): ...

@typing_extensions.dataclass_transform(kw_only_default=True)
class Config:
    __xpmtype__: ClassVar[ObjectType]
    __xpm__: ConfigInformation
    __use_xpmobject__: ClassVar[bool]

    XPMValue: Type[Self]
    XPMConfig: Union[Type[Self], Type[TypeConfig[Self]]]
    C: Union[Type[Self], Type[TypeConfig[Self]]]

    @classmethod
    def __getxpmtype__(cls) -> ObjectType: ...
    def __new__(cls, *args, **kwargs) -> Self: ...
    def __validate__(self) -> None: ...
    def __post_init__(self) -> None: ...
    def __json__(self): ...
    def __identifier__(self) -> Identifier: ...
    def add_pretasks(self, *tasks: "LightweightTask"): ...
    def add_pretasks_from(self, configs: "Config"): ...
    def copy_dependencies(self, other: "Config"): ...
    @property
    def pre_tasks(self) -> List["LightweightTask"]: ...

class LightweightTask(Config):
    def execute(self) -> None: ...

class Task(LightweightTask):
    __tags__: Dict[str, str]

    def submit(
        self,
        *,
        workspace: Incomplete | None = ...,
        launcher: Incomplete | None = ...,
        run_mode: RunMode = ...,
        init_tasks: List["LightweightTask"] = []
    ): ...
    def task_outputs(self, dep: Callable[[Config], None]) -> Any: ...

def copyconfig(config_or_output: TConfig, **kwargs) -> TConfig: ...
def setmeta(config: TConfig, flag: bool) -> TConfig: ...

class TypeConfig(Generic[T]):
    def __validate__(self):
        pass
