from __future__ import annotations
from typing import Protocol, runtime_checkable, Optional, Union
from zempy.zosapi.editors.enums.cell_data_type import CellDataType
from zempy.zosapi.editors.protocols.i_solve_data import ISolveData
from zempy.zosapi.editors.enums.solve_status import SolveStatus

Scalar = Union[int, float, bool]
Value = Union[Scalar, str]


@runtime_checkable
class IEditorCell(Protocol):
    """
    Protocol for ZOSAPI.Editors.IEditorCell.

    Aligned with project conventions:
    - Uses CellDataType enum from editors.enums.cell_data_type
    - Uses ISolveData protocol for solve accessors/mutators
    - ClearSolve/SetSolve return SolveStatus
    """
    # ---- Basic coordinates ----
    @property
    def Row(self) -> int: ...
    @property
    def Column(self) -> int: ...

    # ---- Typing & state ----
    @property
    def DataType(self) -> CellDataType: ...
    @property
    def IsReadOnly(self) -> bool: ...
    @property
    def IsValid(self) -> bool: ...
    @property
    def HasSolve(self) -> bool: ...
    @property
    def HasPickup(self) -> bool: ...

    # ---- Value accessors ----
    @property
    def StringValue(self) -> str: ...
    @property
    def DoubleValue(self) -> float: ...
    @property
    def IntegerValue(self) -> int: ...
    @property
    def BooleanValue(self) -> bool: ...

    # ---- Mutators (typed) ----
    def SetStringValue(self, value: str) -> None: ...
    def SetDoubleValue(self, value: float) -> None: ...
    def SetIntegerValue(self, value: int) -> None: ...
    def SetBooleanValue(self, value: bool) -> None: ...

    # ---- Generic convenience ----
    def SetValue(self, value: Value) -> None: ...
    def Clear(self) -> None: ...
    def ToString(self) -> str: ...

    # ---- Solve / Pickup ----
    def ClearSolve(self) -> SolveStatus: ...
    def SetSolve(self, solve: ISolveData) -> SolveStatus: ...
    def GetSolve(self) -> ISolveData: ...

    def ClearPickup(self) -> None: ...
    def SetPickup(
        self,
        source_row: int,
        source_col: int,
        scale: float = 1.0,
        offset: float = 0.0,
        invert: bool = False,
        operand: Optional[str] = None,
    ) -> None: ...
