"""pyenphase constant definitions"""

import enum

import aiohttp
from awesomeversion import AwesomeVersion

# Versions
LEGACY_ENVOY_VERSION = AwesomeVersion("3.9.0")
ENSEMBLE_MIN_VERSION = AwesomeVersion("5.0.0")
AUTH_TOKEN_MIN_VERSION = AwesomeVersion("7.0.0")
METERED_NOCT_FALLBACK_TO_INVERTERS = AwesomeVersion("8.2.4264")
PRODUCTION_TOTAL_IS_NET_CONSUMPTION = AwesomeVersion("8.3.5433")

# Include in docs from here

# System Production
URL_PRODUCTION_INVERTERS = "/api/v1/production/inverters"
URL_DEVICE_DATA = "/ivp/pdm/device_data"
URL_PRODUCTION_V1 = "/api/v1/production"
URL_PRODUCTION_JSON = "/production.json?details=1"
URL_PRODUCTION = "/production"

# Authentication
URL_AUTH_CHECK_JWT = "/auth/check_jwt"

# Battery and Enpower Status
URL_DRY_CONTACT_STATUS = "/ivp/ensemble/dry_contacts"
URL_DRY_CONTACT_SETTINGS = "/ivp/ss/dry_contact_settings"
URL_ENSEMBLE_INVENTORY = "/ivp/ensemble/inventory"
URL_ENSEMBLE_STATUS = "/ivp/ensemble/status"
URL_ENSEMBLE_SECCTRL = "/ivp/ensemble/secctrl"
URL_ENCHARGE_BATTERY = "/ivp/ensemble/power"
URL_GRID_RELAY = "/ivp/ensemble/relay"
URL_POWER_EXPORT = "/uvp/ss/pel_settings"
URL_TARIFF = "/admin/lib/tariff"
URL_ACB_CONFIG = "/admin/lib/acb_config"
# ?deleted=1 requests that the Envoy include decommissioned devices in the response;
# the updater filters these out by checking admin_state != 0.
URL_INVENTORY = "/inventory.json?deleted=1"

# Generator Configuration
URL_GENERATOR = "/ivp/ensemble/generator"
URL_GEN_CONFIG = "/ivp/ss/gen_config"
URL_GEN_MODE = "/ivp/ss/gen_mode"
URL_GEN_SCHEDULE = "/ivp/ss/gen_schedule"

#: Valid generator modes for :any:`Envoy.set_generator_mode`
GENERATOR_MODES: frozenset[str] = frozenset({"off", "on", "auto"})

#: Settable generator schedule fields for :any:`Envoy.update_generator_schedule`
GENERATOR_SCHEDULE_SETTINGS: frozenset[str] = frozenset(
    {
        "exercise_freq_in_weeks",
        "exercise_day",
        "exercise_start",
        "exercise_duration",
        "default_start_soc",
        "default_stop_soc",
    }
)

#: Valid exercise days for :any:`Envoy.update_generator_schedule`,
#: in the capitalized short-day-name form the generator firmware reports
GENERATOR_EXERCISE_DAYS: tuple[str, ...] = (
    "Mon",
    "Tue",
    "Wed",
    "Thu",
    "Fri",
    "Sat",
    "Sun",
)

# Meters data
ENDPOINT_URL_METERS = "/ivp/meters"
ENDPOINT_URL_METERS_READINGS = "/ivp/meters/readings"

# Interface configuration
ENDPOINT_URL_HOME = "/home"

# Include in docs to here

LOCAL_TIMEOUT = aiohttp.ClientTimeout(
    # The envoy can be slow to respond but fast to connect to we
    # need to set a long timeout for the read and a short timeout
    # for the connect
    total=45.0,
    connect=10.0,
    sock_read=45.0,
)  #: default timeout used for requests

# Requests should no longer retry after max delay (sec) or attempts since first try
# Default is LOCAL_TIMEOUT of 45 sec with some wait time between retries
# which results in retries after 45-90-135-180. max delay of 120 == 3 tries, 150 == 4
DEFAULT_MAX_REQUEST_DELAY = 150  #: default maximum request retry time in seconds
DEFAULT_MAX_REQUEST_ATTEMPTS = 6  #: default maximum request retry attempts
MAX_REQUEST_DELAY = DEFAULT_MAX_REQUEST_DELAY  #: deprecated alias
MAX_REQUEST_ATTEMPTS = DEFAULT_MAX_REQUEST_ATTEMPTS  #: deprecated alias
MAX_PROBE_REQUEST_DELAY = 50  #: maximum elapsed probe retry time in seconds
MAX_PROBE_REQUEST_ATTEMPTS = 4  #: maximum request probe retry attempts


class SupportedFeatures(enum.IntFlag):
    """
    Features available from Envoy

    Each supported feature maps to a specific data set or information
    that can be provided by an Envoy. Depending on actual make, firmware
    and installed components an Envoy may provide 1 or more features.
    All Envoy should at least report solar production, marked as PRODUCTION.

    Class :any:`EnvoyUpdater` updaters will set these features flags
    during the :any:`Envoy.probe` phase. During data collection by
    :any:`Envoy.update` each updater with set features will be used to
    collect the specific data.

    .. code-block:: python

        from pyenphase.const import SupportedFeatures

        # set METERING flag
        features |= SupportedFeatures.METERING

        # test features
        if features.PRODUCTION in supported_features:
            pass

        if features & SupportedFeatures.DUALPHASE:
            pass
    """

    INVERTERS = 1  #: Envoy reports solar panel inverters
    METERING = 2  #: Envoy reports active production meter
    TOTAL_CONSUMPTION = 4  #: Envoy reports total consumption
    NET_CONSUMPTION = 8  #: Envoy reports net consumption
    ENCHARGE = 16  #: Envoy reports encharge data
    ENPOWER = 32  #: Envoy reports Enpower data
    PRODUCTION = 64  #: Envoy reports solar production data
    TARIFF = 128  #: Envoy reports tariff information
    DUALPHASE = 256  #: Envoy metered is configured in split phase mode
    THREEPHASE = 512  #: Envoy metered is configured in three phase mode
    CTMETERS = 1024  #: Envoy has enabled CT meter(s)
    GENERATOR = 2048  #: Envoy reports generator data
    ACB = 4096  #: Envoy reports ACB Battery data
    DETAILED_INVERTERS = 8192  #: Detailed inverter data is reported
    COLLAR = 0x4000  #: Envoy reports a Collar
    C6CC = 0x8000  #: Envoy reports a C6 Combiner controller


class PhaseNames(enum.StrEnum):
    """Electricity grid phase names."""

    PHASE_1 = "L1"  #: first phase (1, A, ..)
    PHASE_2 = "L2"  #: second phase (2, B, ..)
    PHASE_3 = "L3"  #: third phase (3, C, ..)


#: list to access :any:`PhaseNames` by numerical index.
#:
#: .. code-block:: python
#:
#:     phase_count = 2
#:     for phase in range(phase_count):
#:         print(production[PHASENAMES[phase]])
#:
PHASENAMES: list[str] = list(PhaseNames)
