import os
from datetime import timedelta

from pyasic_rs.asic_rs import HashAlgorithm as _rs_HashAlgorithm
from pyasic_rs.asic_rs import Miner as _rs_Miner

from .config import (
    AutoFanConfig,
    FanConfig,
    ManualFanConfig,
    PoolGroup,
    ScalingConfig,
    TuningConfig,
    TuningConfigHashRate,
    TuningConfigMode,
    TuningConfigPower,
)
from .data import (
    MinerData,
    BoardData,
    HashRate,
    FanData,
    MinerMessage,
    PoolGroupData,
    TuningTarget,
    _parse_tuning_target,
)


class Miner:
    def __init__(self, *, inner: _rs_Miner):
        self.__inner = inner

    def __repr__(self):
        return self.__inner.__repr__()

    @property
    def ip(self) -> str:
        return self.__inner.ip

    @property
    def model(self) -> str:
        return self.__inner.model

    @property
    def make(self) -> str:
        return self.__inner.make

    @property
    def firmware(self) -> str:
        return self.__inner.firmware

    @property
    def algo(self) -> _rs_HashAlgorithm:
        return self.__inner.algo

    @property
    def expected_hashboards(self) -> int:
        return self.__inner.expected_hashboards

    @property
    def expected_chips(self) -> int:
        return self.__inner.expected_chips

    @property
    def expected_fans(self) -> int:
        return self.__inner.expected_fans

    async def get_data(self) -> MinerData:
        return MinerData.model_validate(await self.__inner.get_data())

    async def get_mac(self) -> str | None:
        return await self.__inner.get_mac()

    async def get_serial_number(self) -> str | None:
        return await self.__inner.get_serial_number()

    async def get_hostname(self) -> str | None:
        return await self.__inner.get_hostname()

    async def get_api_version(self) -> str | None:
        return await self.__inner.get_api_version()

    async def get_firmware_version(self) -> str | None:
        return await self.__inner.get_firmware_version()

    async def get_control_board_version(self) -> str | None:
        return await self.__inner.get_control_board_version()

    async def get_hashboards(self) -> list[BoardData]:
        return [
            BoardData.model_validate(b) for b in await self.__inner.get_hashboards()
        ]

    async def get_hashrate(self) -> HashRate | None:
        inner = await self.__inner.get_hashrate()
        if inner is not None:
            return HashRate.model_validate(inner)
        return None

    async def get_expected_hashrate(self) -> HashRate | None:
        inner = await self.__inner.get_expected_hashrate()
        if inner is not None:
            return HashRate.model_validate(inner)
        return None

    async def get_fans(self) -> list[FanData]:
        return [FanData.model_validate(f) for f in await self.__inner.get_fans()]

    async def get_psu_fans(self) -> list[FanData]:
        return [FanData.model_validate(f) for f in await self.__inner.get_psu_fans()]

    async def get_fluid_temperature(self) -> float | None:
        return await self.__inner.get_fluid_temperature()

    async def get_wattage(self) -> float | None:
        return await self.__inner.get_wattage()

    async def get_tuning_target(self) -> TuningTarget | None:
        inner = await self.__inner.get_tuning_target()
        if inner is None:
            return None
        parsed = _parse_tuning_target(inner)
        if isinstance(parsed, TuningTarget):
            return parsed
        raise TypeError(
            f"Unexpected tuning target type from _parse_tuning_target: {type(parsed)!r}"
        )

    async def get_light_flashing(self) -> bool | None:
        return await self.__inner.get_light_flashing()

    async def get_messages(self) -> list[MinerMessage]:
        return [
            MinerMessage.model_validate(m) for m in await self.__inner.get_messages()
        ]

    async def get_uptime(self) -> timedelta | None:
        return await self.__inner.get_uptime()

    async def get_is_mining(self) -> bool | None:
        return await self.__inner.get_is_mining()

    async def get_pools(self) -> list[PoolGroupData]:
        return [PoolGroupData.model_validate(b) for b in await self.__inner.get_pools()]

    async def get_pools_config(self) -> list[PoolGroup] | None:
        inner = await self.__inner.get_pools_config()
        if inner is not None:
            return [PoolGroup.model_validate(group) for group in inner]
        return None

    async def set_fault_light(self, fault: bool) -> bool | None:
        return await self.__inner.set_fault_light(fault)

    async def restart(self) -> bool | None:
        return await self.__inner.restart()

    async def pause(self, at_time: timedelta | int) -> bool | None:
        if isinstance(at_time, int):
            at_time = timedelta(seconds=at_time)
        return await self.__inner.pause(at_time)

    async def resume(self, at_time: timedelta | int) -> bool | None:
        if isinstance(at_time, int):
            at_time = timedelta(seconds=at_time)
        return await self.__inner.resume(at_time)

    async def get_scaling_config(self) -> ScalingConfig | None:
        inner = await self.__inner.get_scaling_config()
        if inner is not None:
            return ScalingConfig.model_validate(inner)
        return None

    async def get_tuning_config(
        self,
    ) -> TuningConfigPower | TuningConfigHashRate | TuningConfigMode | None:
        inner = await self.__inner.get_tuning_config()
        if inner is not None:
            return TuningConfig.model_validate(inner)
        return None

    async def get_fan_config(self) -> FanConfig | None:
        inner = await self.__inner.get_fan_config()
        if inner is None:
            return None
        mode = str(inner.mode).lower()
        if mode == "auto":
            return AutoFanConfig.model_validate(inner)
        if mode == "manual":
            return ManualFanConfig.model_validate(inner)
        return None

    async def set_pools_config(self, groups: list[PoolGroup]) -> bool | None:
        return await self.__inner.set_pools_config(groups)

    async def set_power_limit(self, watts: float) -> bool | None:
        return await self.__inner.set_power_limit(watts)

    async def set_scaling_config(self, config: ScalingConfig) -> bool | None:
        return await self.__inner.set_scaling_config(config)

    async def set_tuning_config(
        self,
        config: TuningConfigPower | TuningConfigHashRate | TuningConfigMode,
        scaling_config: ScalingConfig | None = None,
    ) -> bool | None:
        return await self.__inner.set_tuning_config(config, scaling_config)

    async def set_fan_config(self, config: FanConfig) -> bool | None:
        return await self.__inner.set_fan_config(config)

    async def upgrade_firmware(self, path: str | os.PathLike[str]) -> None:
        return await self.__inner.upgrade_firmware(path)

    @property
    def supports_set_fault_light(self) -> bool:
        return self.__inner.supports_set_fault_light

    @property
    def supports_set_power_limit(self) -> bool:
        return self.__inner.supports_set_power_limit

    @property
    def supports_restart(self) -> bool:
        return self.__inner.supports_restart

    @property
    def supports_pause(self) -> bool:
        return self.__inner.supports_pause

    @property
    def supports_resume(self) -> bool:
        return self.__inner.supports_resume

    @property
    def supports_pools_config(self) -> bool:
        return self.__inner.supports_pools_config

    @property
    def supports_scaling_config(self) -> bool:
        return self.__inner.supports_scaling_config

    @property
    def supports_tuning_config(self) -> bool:
        return self.__inner.supports_tuning_config

    @property
    def supports_fan_config(self) -> bool:
        return self.__inner.supports_fan_config

    @property
    def supports_upgrade_firmware(self) -> bool:
        return self.__inner.supports_upgrade_firmware

    def set_auth(self, username: str, password: str) -> None:
        self.__inner.set_auth(username, password)
