"""Data models."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import voluptuous as vol  # type: ignore[import]


@dataclass
class Timestamp:
    """Timestamp."""

    SCHEMA = vol.Schema(
        {
            vol.Optional("authoritative"): bool,
            vol.Optional("seconds"): int,
            vol.Optional("ticks"): int,
        }
    )

    authoritative: bool | None = None
    seconds: int | None = None
    ticks: int | None = None

    def as_json(self) -> dict:
        """Serialize to JSON."""
        result: dict[str, Any] = {}
        if self.authoritative is not None:
            result["authoritative"] = self.authoritative
        if self.seconds is not None:
            result["seconds"] = self.seconds
        if self.ticks is not None:
            result["ticks"] = self.ticks
        return result

    @classmethod
    def from_json(cls, json_data: Any) -> Timestamp:
        """Deserialize from JSON."""
        cls.SCHEMA(json_data)
        return cls(
            json_data.get("authoritative"),
            json_data.get("seconds"),
            json_data.get("ticks"),
        )


@dataclass
class SecurityPolicy:  # pylint: disable=too-many-instance-attributes
    """Security policy."""

    SCHEMA = vol.Schema(
        {
            vol.Optional("autonomousEnrollment"): bool,
            vol.Optional("commercialCommissioning"): bool,
            vol.Optional("externalCommissioning"): bool,
            vol.Optional("nativeCommissioning"): bool,
            vol.Optional("networkKeyProvisioning"): bool,
            vol.Optional("nonCcmRouters"): bool,
            vol.Optional("obtainNetworkKey"): bool,
            vol.Optional("rotationTime"): int,
            vol.Optional("routers"): bool,
            vol.Optional("tobleLink"): bool,
        }
    )

    autonomous_enrollment: bool | None = None
    commercial_commissioning: bool | None = None
    external_commissioning: bool | None = None
    native_commissioning: bool | None = None
    network_key_provisioning: bool | None = None
    non_ccm_routers: bool | None = None
    obtain_network_key: bool | None = None
    rotation_time: int | None = None
    routers: bool | None = None
    to_ble_link: bool | None = None

    def as_json(self) -> dict:
        """Serialize to JSON."""
        result: dict[str, Any] = {}
        if self.autonomous_enrollment is not None:
            result["autonomousEnrollment"] = self.autonomous_enrollment
        if self.commercial_commissioning is not None:
            result["commercialCommissioning"] = self.commercial_commissioning
        if self.external_commissioning is not None:
            result["externalCommissioning"] = self.external_commissioning
        if self.native_commissioning is not None:
            result["nativeCommissioning"] = self.native_commissioning
        if self.network_key_provisioning is not None:
            result["networkKeyProvisioning"] = self.network_key_provisioning
        if self.non_ccm_routers is not None:
            result["nonCcmRouters"] = self.non_ccm_routers
        if self.obtain_network_key is not None:
            result["obtainNetworkKey"] = self.obtain_network_key
        if self.rotation_time is not None:
            result["rotationTime"] = self.rotation_time
        if self.routers is not None:
            result["routers"] = self.routers
        if self.to_ble_link is not None:
            result["tobleLink"] = self.to_ble_link
        return result

    @classmethod
    def from_json(cls, json_data: Any) -> SecurityPolicy:
        """Deserialize from JSON."""
        cls.SCHEMA(json_data)
        return cls(
            json_data.get("autonomousEnrollment"),
            json_data.get("commercialCommissioning"),
            json_data.get("externalCommissioning"),
            json_data.get("nativeCommissioning"),
            json_data.get("networkKeyProvisioning"),
            json_data.get("nonCcmRouters"),
            json_data.get("obtainNetworkKey"),
            json_data.get("rotationTime"),
            json_data.get("routers"),
            json_data.get("tobleLink"),
        )


@dataclass
class ActiveDataSet:  # pylint: disable=too-many-instance-attributes
    """Operational dataset."""

    SCHEMA = vol.Schema(
        {
            vol.Optional("activeTimestamp"): dict,
            vol.Optional("channelMask"): int,
            vol.Optional("channel"): int,
            vol.Optional("extPanId"): str,
            vol.Optional("meshLocalPrefix"): str,
            vol.Optional("networkKey"): str,
            vol.Optional("networkName"): str,
            vol.Optional("panId"): int,
            vol.Optional("pskc"): str,
            vol.Optional("securityPolicy"): dict,
        }
    )

    active_timestamp: Timestamp | None = None
    channel_mask: int | None = None
    channel: int | None = None
    extended_pan_id: str | None = None
    mesh_local_prefix: str | None = None
    network_key: str | None = None
    network_name: str | None = None
    pan_id: int | None = None
    psk_c: str | None = None
    security_policy: SecurityPolicy | None = None

    def as_json(self) -> dict:
        """Serialize to JSON."""
        result: dict[str, Any] = {}
        if self.active_timestamp is not None:
            result["activeTimestamp"] = self.active_timestamp.as_json()
        if self.channel_mask is not None:
            result["channelMask"] = self.channel_mask
        if self.channel is not None:
            result["channel"] = self.channel
        if self.extended_pan_id is not None:
            result["extPanId"] = self.extended_pan_id
        if self.mesh_local_prefix is not None:
            result["meshLocalPrefix"] = self.mesh_local_prefix
        if self.network_key is not None:
            result["networkKey"] = self.network_key
        if self.network_name is not None:
            result["networkName"] = self.network_name
        if self.pan_id is not None:
            result["panId"] = self.pan_id
        if self.psk_c is not None:
            result["pskc"] = self.psk_c
        if self.security_policy is not None:
            result["securityPolicy"] = self.security_policy.as_json()
        return result

    @classmethod
    def from_json(cls, json_data: Any) -> ActiveDataSet:
        """Deserialize from JSON."""
        cls.SCHEMA(json_data)
        active_timestamp = None
        security_policy = None
        if "activeTimestamp" in json_data:
            active_timestamp = Timestamp.from_json(json_data["activeTimestamp"])
        if "securityPolicy" in json_data:
            security_policy = SecurityPolicy.from_json(json_data["securityPolicy"])

        return ActiveDataSet(
            active_timestamp,
            json_data.get("channelMask"),
            json_data.get("channel"),
            json_data.get("extPanId"),
            json_data.get("meshLocalPrefix"),
            json_data.get("networkKey"),
            json_data.get("networkName"),
            json_data.get("panId"),
            json_data.get("pskc"),
            security_policy,
        )


@dataclass
class PendingDataSet:  # pylint: disable=too-many-instance-attributes
    """Operational dataset."""

    SCHEMA = vol.Schema(
        {
            vol.Optional("activeDataset"): dict,
            vol.Optional("delay"): int,
            vol.Optional("pendingTimestamp"): dict,
        }
    )

    active_dataset: ActiveDataSet | None = None
    delay: int | None = None
    pending_timestamp: Timestamp | None = None

    def as_json(self) -> dict:
        """Serialize to JSON."""
        result: dict[str, Any] = {}
        if self.active_dataset is not None:
            result["activeDataset"] = self.active_dataset.as_json()
        if self.delay is not None:
            result["delay"] = self.delay
        if self.pending_timestamp is not None:
            result["pendingTimestamp"] = self.pending_timestamp.as_json()
        return result

    @classmethod
    def from_json(cls, json_data: Any) -> PendingDataSet:
        """Deserialize from JSON."""
        cls.SCHEMA(json_data)
        active_dataset = None
        pending_timestamp = None
        if "activeDataset" in json_data:
            active_dataset = ActiveDataSet.from_json(json_data["activeDataset"])
        if "pendingTimestamp" in json_data:
            pending_timestamp = Timestamp.from_json(json_data["pendingTimestamp"])

        return PendingDataSet(
            active_dataset,
            json_data.get("delay"),
            pending_timestamp,
        )
