from typing import (
    Any,
    Dict,
    Hashable,
    List,
    Iterable,
    Mapping,
    Optional,
    Sequence,
    Tuple,
    Union,
    overload
)
import pandas as pd
from .dataframe import DataFrame
from .outputhandler import Kind


AMPLVariant = Optional[Union[int, float, str]]
AMPLTuple = Union[int, float, str, List[Union[int, float, str]], List[Union[int, float, str]]]

class Entity:
    def to_string(self) -> str: ...
    def toString(self) -> str: ...
    def __str__(self) -> str: ...
    def __iter__(self) -> Iterable[Entity]: ...
    def __getitem__(self, index: AMPLTuple) -> Entity: ...
    def get(self, *index: AMPLTuple) -> Entity: ...
    def find(self, index: AMPLTuple) -> Optional[Entity]: ...
    def instances(self) -> Iterable[Entity]: ...
    def name(self) -> str: ...
    def indexarity(self) -> int: ...
    def is_scalar(self) -> bool: ...
    def isScalar(self) -> bool: ...
    def num_instances(self) -> int: ...
    def numInstances(self) -> int: ...
    def get_indexing_sets(self) -> List[Optional[str]]: ...
    def getIndexingSets(self) -> List[Optional[str]]: ...
    def xref(self) -> List[Optional[str]]: ...
    def get_values(self, suffixes: Optional[Union[str, Iterable[str]]] = None) -> Any: ...
    def getValues(self, suffixes: Optional[Union[str, Iterable[str]]] = None) -> Any: ...
    def to_pandas(self, **kwargs: Any) -> pd.DataFrame: ...
    def to_dict(self, **kwargs: Any) -> Dict[Hashable, Any]: ...
    def to_list(self, **kwargs: Any) -> List[Union[Any, Tuple[Any, ...]]]: ...
    def set_values(self, data: Union[ DataFrame, Dict[Hashable, Any], pd.DataFrame, pd.Series]) -> None: ...
    def setValues(self, data: Union[ DataFrame, Dict[Hashable, Any], pd.DataFrame, pd.Series]) -> None: ...

class Constraint(Entity):
    def __setitem__(self, index: AMPLTuple, value: float) -> None: ...
    def is_logical(self) -> bool: ...
    def isLogical(self) -> bool: ...
    def drop(self) -> None: ...
    def restore(self) -> None: ...
    def body(self) -> float: ...
    def astatus(self) -> str: ...
    def defvar(self) -> int: ...
    def dinit(self) -> float: ...
    def dinit0(self) -> float: ...
    def dual(self) -> float: ...
    def lb(self) -> float: ...
    def ub(self) -> float: ...
    def lbs(self) -> float: ...
    def ubs(self) -> float: ...
    def ldual(self) -> float: ...
    def udual(self) -> float: ...
    def lslack(self) -> float: ...
    def uslack(self) -> float: ...
    def slack(self) -> float: ...
    def sstatus(self) -> str: ...
    def status(self) -> str: ...
    def set_dual(self, dual: Union[int, float]) -> None: ...
    def setDual(self, dual: Union[int, float]) -> None: ...
    def val(self) -> Optional[float]: ...

class Objective(Entity):
    def value(self) -> float: ...
    def astatus(self) -> str: ...
    def sstatus(self) -> str: ...
    def exitcode(self) -> int: ...
    def message(self) -> str: ...
    def result(self) -> str: ...
    def drop(self) -> None: ...
    def restore(self) -> None: ...
    def minimization(self) -> bool: ...

class Parameter:
    def __setitem__(self, index: AMPLTuple, value: AMPLVariant) -> None: ...
    def is_symbolic(self) -> bool: ...
    def isSymbolic(self) -> bool: ...
    def has_default(self) -> bool: ...
    def hasDefault(self) -> bool: ...
    def __getitem__(self, index: AMPLTuple) -> AMPLVariant: ...
    def value(self) -> AMPLVariant: ...
    def set(self, *args: Any) -> None: ...
    def set_values(self, values: Any) -> None: ...
    def setValues(self, values: Any) -> None: ...

class Set:
    def __setitem__(self, index: Any, value: Any) -> None: ...
    def __iter__(self) -> Union[Iterable[Any], Iterable[Tuple[Any, ...]]]: ...
    def instances(self) -> Iterable[Entity]: ...
    def arity(self) -> int: ...
    def get_values(self) -> DataFrame: ...
    def getValues(self) -> DataFrame: ...
    def members(self) -> Iterable[Tuple[Any, ...]]: ...
    def size(self) -> int: ...
    def contains(self, t: AMPLTuple) -> bool: ...
    def set_values(self, values: Union[DataFrame, Iterable[Union[str, int, float, Iterable[Union[str, int, float]]]]]) -> None: ...
    def setValues(self, values: Union[DataFrame, Iterable[Union[str, int, float, Iterable[Union[str, int, float]]]]]) -> None: ...

class Variable(Entity):
    def __setitem__(self, index: AMPLTuple, value: Union[float, int, Parameter]) -> None: ...
    def value(self) -> float: ...
    def fix(self, value: Optional[float] = None) -> None: ...
    def unfix(self) -> None: ...
    def set_value(self, value: Union[float, int, Parameter]) -> None: ...
    def setValue(self, value: Union[float, int, Parameter]) -> None: ...
    def astatus(self) -> str: ...
    def defeqn(self) -> int: ...
    def dual(self) -> float: ...
    def init(self) -> float: ...
    def init0(self) -> float: ...
    def lb(self) -> float: ...
    def ub(self) -> float: ...
    def lb0(self) -> float: ...
    def ub0(self) -> float: ...
    def lb1(self) -> float: ...
    def ub1(self) -> float: ...
    def lb2(self) -> float: ...
    def ub2(self) -> float: ...
    def lrc(self) -> float: ...
    def urc(self) -> float: ...
    def lslack(self) -> float: ...
    def uslack(self) -> float: ...
    def rc(self) -> float: ...
    def slack(self) -> float: ...
    def sstatus(self) -> str: ...
    def status(self) -> str: ...

class EntityMap:
    def __iter__(self) -> EntityMap: ...
    def __next__(self) -> Tuple[str, Union[Entity, Constraint, Objective, Parameter, Set, Variable]]: ...
    def __getitem__(self, key: str) -> Union[Entity, Constraint, Objective, Parameter, Set, Variable]: ...
    def size(self) -> int: ...
    def __len__(self) -> int: ...

# Nominal wrappers to model the helpers returned by AMPL._var/_con/... ---

class Variables:
    def __getitem__(self, name: str) -> Variable: ...
    @overload
    def __setitem__(self, name: str, value: float) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Iterable[float]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Mapping[Any, float]) -> None: ...
    def __setitem__(self, name: str, value: Union[float, Iterable[float], Mapping[Any, float]]) -> None: ...

class Constraints:
    def __getitem__(self, name: str) -> Constraint: ...
    @overload
    def __setitem__(self, name: str, value: float) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Iterable[float]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Mapping[Any, float]) -> None: ...
    def __setitem__(self, name: str, value: Union[float, Iterable[float], Mapping[Any, float]]) -> None: ...

class Objectives:
    def __getitem__(self, name: str) -> Objective: ...
    def __iter__(self) -> Iterable[Objective]: ...

class Sets:
    def __getitem__(self, name: str) -> Set: ...
    def __setitem__(self, name: str, values: Iterable[Any]) -> None: ...
    def __iter__(self) -> Iterable[Set]: ...

class Parameters:
    def __getitem__(self, name: str) -> Parameter: ...
    @overload
    def __setitem__(self, name: str, value: Union[float, str]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Mapping[Any, float]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Iterable[Tuple[Any, float]]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: Iterable[float]) -> None: ...
    def __setitem__(self, name: str, value: Union[float, str, Mapping[Any, float], Iterable[Tuple[Any, float]], Iterable[float]]) -> None: ...
    def __iter__(self) -> Iterable[Parameter]: ...

class Options:
    def __getitem__(self, name: str) -> Optional[Union[int, float, str]]: ...
    @overload
    def __setitem__(self, name: str, value: Mapping[str, Union[int, float, str, bool]]) -> None: ...
    @overload
    def __setitem__(self, name: str, value: object) -> None: ...
    def __setitem__(self, name: str, value: Union[Mapping[str, Union[int, float, str, bool]], object]) -> None: ...

class Environment:
    def __str__(self) -> str: ...
    def __iter__(self) -> object: ...
    def __setitem__(self, name: str, value: str) -> None: ...
    def __getitem__(self, name: str) -> Union[str, None]: ...
    def to_string(self) -> str: ...
    def set_bin_dir(self, binary_directory: str) -> None: ...
    def get_bin_dir(self) -> str: ...
    def set_bin_name(self, binary_name: str) -> None: ...
    def get_bin_name(self) -> str: ...

class OutputHandler:
    def output(self, kind: Kind, msg: str) -> None: ...

class ErrorHandler:
    def error(self, exception: type[BaseException]) -> None: ...
    def warning(self, exception: type[BaseException]) -> None: ...

class AMPL:
    var: Variables
    con: Constraints
    obj: Objectives
    set: Sets
    param: Parameters
    option: Options
    def __init__(self, environment: Optional[Environment] = None) -> None: ...
    def get_data(self, statements: Sequence[str]) -> DataFrame: ...
    def getData(self, statements: Sequence[str]) -> DataFrame: ...
    def get_entity(self, name: str) -> Entity: ...
    def getEntity(self, name: str) -> Entity: ...
    def get_variable(self, name: str) -> Variable: ...
    def getVariable(self, name: str) -> Variable: ...
    def get_constraint(self, name: str) -> Constraint: ...
    def getConstraint(self, name: str) -> Constraint: ...
    def get_objective(self, name: str) -> Objective: ...
    def getObjective(self, name: str) -> Objective: ...
    def get_set(self, name: str) -> Set: ...
    def getSet(self, name: str) -> Set: ...
    def get_parameter(self, name: str) -> Parameter: ...
    def getParameter(self, name: str) -> Parameter: ...
    def eval(self, statements: str) -> None: ...
    def get_output(self, statements: str) -> str: ...
    def getOutput(self, statements: str) -> str: ...
    def reset(self) -> None: ...
    def close(self) -> None: ...
    def is_running(self) -> bool: ...
    def isRunning(self) -> bool: ...
    def solve(self, problem: Optional[str] = "", solver: Optional[str] = "", verbose: bool = True, return_output: bool = False, **kwargs: Any) -> None: ...
    def cd(self, path: Optional[str] = None) -> str: ...
    def set_option(self, name: str, value: Union[bool, int, float, str]) -> None: ...
    def setOption(self, name: str, value: Union[bool, int, float, str]) -> None: ...
    def get_option(self, name: str) -> Union[bool, int, float, str]: ...
    def getOption(self, name: str) -> Union[bool, int, float, str]: ...
    def read(self, filename: str) -> None: ...
    def read_data(self, filename: str) -> None: ...
    def readData(self, filename: str) -> None: ...
    def get_value(self, scalar_expression: str) -> AMPLVariant: ...
    def getValue(self, scalar_expression: str) -> AMPLVariant: ...
    def set_data(self, data: Union[DataFrame, pd.DataFrame, pd.Series], set_name: Optional[str] = None) -> None: ...
    def setData(self, data: Union[DataFrame, pd.DataFrame, pd.Series], set_name: Optional[str] = None) -> None: ...
    def read_table(self, table_name: str) -> None: ...
    def readTable(self, table_name: str) -> None: ...
    def write_table(self, table_name: str) -> None: ...
    def writeTable(self, table_name: str) -> None: ...
    def display(self, *ampl_expressions: Any) -> None: ...
    def set_output_handler(self, output_handler: OutputHandler) -> None: ...
    def setOutputHandler(self, output_handler: OutputHandler) -> None: ...
    def set_error_handler(self, error_handler: ErrorHandler) -> None: ...
    def setErrorHandler(self, error_handler: ErrorHandler) -> None: ...
    def get_output_handler(self) -> OutputHandler: ...
    def getOutputHandler(self) -> OutputHandler: ...
    def get_error_handler(self) -> ErrorHandler: ...
    def getErrorHandler(self) -> ErrorHandler: ...
    def get_variables(self) -> EntityMap: ...
    def getVariables(self) -> EntityMap: ...
    def get_constraints(self) -> EntityMap: ...
    def getConstraints(self) -> EntityMap: ...
    def get_objectives(self) -> EntityMap: ...
    def getObjectives(self) -> EntityMap: ...
    def get_sets(self) -> EntityMap: ...
    def getSets(self) -> EntityMap: ...
    def get_parameters(self) -> EntityMap: ...
    def getParameters(self) -> EntityMap: ...
    def get_current_objective(self) -> Optional[Objective]: ...
    def getCurrentObjective(self) -> Optional[Objective]: ...
    def _var(self) -> Variables: ...
    def _con(self) -> Constraints: ...
    def _obj(self) -> Objectives: ...
    def _set(self) -> Sets: ...
    def _param(self) -> Parameters: ...
    def _option(self) -> Options: ...
    def _set_option(self, options_dict:  Dict[str, Any]) -> None: ...
    def export_model(self, filename: str = "") -> str: ...
    def exportModel(self, filename: str = "") -> str: ...
    def export_data(self, filename: str = "") -> str: ...
    def exportData(self, filename: str = "") -> str: ...
    def snapshot(self, filename: str = "", model: bool = True, data: bool = True, options: bool = True) -> str: ...
    def write(self, filename: str, auxfiles:str = "") -> None: ...
    @property
    def solve_result(self) -> AMPLVariant: ...
    @property
    def solve_result_num(self) -> AMPLVariant: ...
    def get_iis(self, flat: bool = True) -> Tuple[Dict[str, Any], Dict[str, Any]]: ...    
    def get_solution(self, flat: bool = True, zeros: bool = False) -> Dict[str, Any]: ...    
    def _start_recording(self, filename: str) -> None: ...
    def _startRecording(self, filename: str) -> None: ...
    def _stop_recording(self) -> None: ...
    def _stopRecording(self) -> None: ...
    def _load_session(self, filename: str) -> None: ...
    def _loadSession(self, filename: str) -> None: ...
    def to_ampls(self, driver: str, options: Optional[Mapping[str, Any]] = ...) -> Any: ...
    def import_ampls_solution(
        self,
        model: Any,
        number: Optional[int] = ...,
        import_entities: bool = ...,
        keep_files: bool = ...
    ) -> None: ...
    def toString(self) -> str: ...
    def __str__(self) -> str: ...
