"""HTTP client for Heiman Cloud API."""

import logging
from typing import Any, Optional

import aiohttp

from .auth import HeimanAuth
from .exceptions import HeimanApiError, HeimanAuthError, HeimanConnectionError
from .models import HeimanDevice, HeimanHome, HeimanUser

_LOGGER = logging.getLogger(__name__)


class HeimanHttpClient:
    """Low-level HTTP client for Heiman API.
    
    This class handles the raw HTTP requests with proper authentication headers.
    """

    def __init__(
        self,
        api_url: str,
        client_id: str,
        access_token: Optional[str] = None,
    ) -> None:
        """Initialize HTTP client.
        
        Args:
            api_url: Base API URL
            client_id: OAuth2 client ID
            access_token: Access token for authentication
        """
        self.api_url = api_url.rstrip("/")
        self.client_id = client_id
        self.access_token = access_token
        self._session: Optional[aiohttp.ClientSession] = None

    async def _get_session(self) -> aiohttp.ClientSession:
        """Get or create aiohttp session."""
        if self._session is None or self._session.closed:
            self._session = aiohttp.ClientSession()
        return self._session

    async def close(self) -> None:
        """Close the HTTP session."""
        if self._session and not self._session.closed:
            await self._session.close()

    def _get_headers(self) -> dict[str, str]:
        """Get request headers with authentication."""
        headers = {
            "Content-Type": "application/json",
            "Accept": "application/json",
        }
        
        if self.access_token:
            headers["Authorization"] = f"Bearer {self.access_token}"
        
        return headers

    async def request(
        self,
        method: str,
        endpoint: str,
        data: Optional[dict[str, Any]] = None,
        params: Optional[dict[str, Any]] = None,
    ) -> dict[str, Any]:
        """Make HTTP request to Heiman API.
        
        Args:
            method: HTTP method (GET, POST, PUT, DELETE)
            endpoint: API endpoint path
            data: Request body data
            params: Query parameters
            
        Returns:
            JSON response as dictionary
            
        Raises:
            HeimanConnectionError: If network request fails
            HeimanApiError: If API returns error
        """
        url = f"{self.api_url}{endpoint}"
        headers = self._get_headers()

        try:
            session = await self._get_session()
            
            async with session.request(
                method,
                url,
                json=data if method in ["POST", "PUT"] else None,
                params=params if method == "GET" else None,
                headers=headers,
            ) as response:
                result = await response.json()
                
                if response.status >= 400:
                    error_msg = result.get("message", "Unknown API error")
                    error_code = result.get("code")
                    
                    if response.status == 401:
                        raise HeimanAuthError(
                            message="Authentication failed - token may be expired",
                            error_code=error_code,
                            raw_response=result,
                        )
                    
                    raise HeimanApiError(
                        message=error_msg,
                        error_code=error_code,
                        raw_response=result,
                    )
                
                return result
                
        except aiohttp.ClientError as err:
            raise HeimanConnectionError(
                message=f"Network error: {str(err)}",
            ) from err
        except Exception as err:
            raise HeimanApiError(
                message=f"Unexpected error: {str(err)}",
            ) from err

    async def get(
        self,
        endpoint: str,
        params: Optional[dict[str, Any]] = None,
    ) -> dict[str, Any]:
        """Make GET request."""
        return await self.request("GET", endpoint, params=params)

    async def post(
        self,
        endpoint: str,
        data: Optional[dict[str, Any]] = None,
    ) -> dict[str, Any]:
        """Make POST request."""
        return await self.request("POST", endpoint, data=data)

    async def put(
        self,
        endpoint: str,
        data: Optional[dict[str, Any]] = None,
    ) -> dict[str, Any]:
        """Make PUT request."""
        return await self.request("PUT", endpoint, data=data)

    async def delete(
        self,
        endpoint: str,
    ) -> dict[str, Any]:
        """Make DELETE request."""
        return await self.request("DELETE", endpoint)

    def update_access_token(self, access_token: str) -> None:
        """Update access token.
        
        Args:
            access_token: New access token
        """
        self.access_token = access_token
        _LOGGER.debug("Access token updated")


class HeimanCloudClient:
    """High-level Heiman cloud API client.
    
    This class provides convenient methods for common API operations
    like getting users, homes, and devices.
    """

    def __init__(
        self,
        http_client: HeimanHttpClient,
        auth: HeimanAuth,
    ) -> None:
        """Initialize cloud client.
        
        Args:
            http_client: Low-level HTTP client instance
            auth: Authentication manager instance
        """
        self.http_client = http_client
        self.auth = auth
        self._home_id: Optional[str] = None
        self._user_id: Optional[str] = None

    @property
    def home_id(self) -> Optional[str]:
        """Get current home ID."""
        return self._home_id

    @home_id.setter
    def home_id(self, value: str) -> None:
        """Set current home ID."""
        self._home_id = value

    @property
    def user_id(self) -> Optional[str]:
        """Get current user ID."""
        return self._user_id or self.auth.user_id

    async def _ensure_authenticated(self) -> None:
        """Ensure we have a valid access token."""
        if not self.auth.is_authenticated:
            raise HeimanAuthError(message="Not authenticated")
        
        # Ensure token is valid and refresh if needed
        access_token = await self.auth.ensure_valid_token()
        self.http_client.update_access_token(access_token)

    async def async_get_user_info(self) -> HeimanUser:
        """Get current user information.
        
        Returns:
            HeimanUser object with user details
            
        Raises:
            HeimanApiError: If API request fails
        """
        await self._ensure_authenticated()
        
        endpoint = "/api-app/appUser/get/info"
        result = await self.http_client.post(endpoint)
        
        user_data = result.get("data", {})
        
        user = HeimanUser(
            user_id=user_data.get("id", ""),
            email=user_data.get("email", ""),
            nickname=user_data.get("nickname"),
            phone=user_data.get("phone"),
            avatar=user_data.get("avatar"),
            raw_data=user_data,
        )
        
        self._user_id = user.user_id
        return user

    async def async_get_homes(self) -> list[HeimanHome]:
        """Get list of homes for current user.
        
        Returns:
            List of HeimanHome objects
            
        Raises:
            HeimanApiError: If API request fails
        """
        await self._ensure_authenticated()
        
        endpoint = "/api-app/homeUserRelation/get/homeList"
        data = {"userId": self.user_id}
        result = await self.http_client.post(endpoint, data=data)
        
        homes_data = result.get("data", [])
        
        homes = []
        for home_data in homes_data:
            home = HeimanHome(
                home_id=home_data.get("homeId", ""),
                home_name=home_data.get("homeName", ""),
                user_id=home_data.get("userId", ""),
                room_count=home_data.get("roomCount", 0),
                device_count=home_data.get("deviceCount", 0),
                cover_url=home_data.get("coverUrl"),
                raw_data=home_data,
            )
            homes.append(home)
        
        _LOGGER.debug(f"Retrieved {len(homes)} homes")
        return homes

    async def async_get_devices(
        self,
        home_id: Optional[str] = None,
        page_number: int = 1,
        page_size: int = 100,
    ) -> dict[str, HeimanDevice]:
        """Get list of devices in specified home.
        
        Args:
            home_id: Home ID (uses current home_id if not specified)
            page_number: Page number for pagination
            page_size: Number of devices per page
            
        Returns:
            Dictionary mapping device_id to HeimanDevice objects
            
        Raises:
            HeimanApiError: If API request fails
        """
        await self._ensure_authenticated()
        
        target_home_id = home_id or self._home_id
        if not target_home_id:
            raise HeimanApiError(message="No home ID specified")
        
        endpoint = "/api-app/device/get/listByPage"
        
        # Build request data according to protocol
        request_data = {
            "help": {
                "pageSize": page_size,
                "pageNumber": page_number,
            },
            "custom": {
                "homeId": target_home_id,
                "secureId": "",  # Can be set if available
                "userId": self.user_id,
                # Request all property identifiers
                "propertyIdentifiers": [],
            },
        }
        
        result = await self.http_client.post(endpoint, data=request_data)
        
        devices_data = result.get("data", {}).get("list", [])
        total = result.get("data", {}).get("total", 0)
        
        devices = {}
        for device_data in devices_data:
            device = self._parse_device_data(device_data)
            devices[device.device_id] = device
        
        _LOGGER.debug(f"Retrieved {len(devices)} devices (total: {total})")
        return devices

    def _parse_device_data(self, device_data: dict[str, Any]) -> HeimanDevice:
        """Parse raw device data into HeimanDevice object.
        
        Args:
            device_data: Raw device data from API
            
        Returns:
            HeimanDevice object
        """
        # Extract basic device info
        device_info = device_data.get("deviceInfo", {})
        properties_data = device_data.get("properties", [])
        
        # Parse properties
        properties = {}
        for prop_data in properties_data:
            identifier = prop_data.get("identifier", "")
            prop = DeviceProperty(
                identifier=identifier,
                name=prop_data.get("name", identifier),
                value=prop_data.get("value"),
                unit=prop_data.get("unit"),
                data_type=prop_data.get("dataType"),
                readable=prop_data.get("readable", True),
                writable=prop_data.get("writable", False),
                description=prop_data.get("description"),
            )
            properties[identifier] = prop
        
        # Create device object
        device = HeimanDevice(
            device_id=device_info.get("deviceId", ""),
            device_name=device_info.get("deviceName", ""),
            product_id=device_info.get("productId", ""),
            home_id=device_info.get("homeId", ""),
            room_id=device_info.get("roomId"),
            device_type=device_info.get("deviceType"),
            model=device_info.get("model"),
            firmware_version=device_info.get("firmwareVersion"),
            hardware_version=device_info.get("hardwareVersion"),
            serial_number=device_info.get("serialNumber"),
            mac_address=device_info.get("macAddress"),
            ip_address=device_info.get("ipAddress"),
            online=device_info.get("online", False),
            properties=properties,
            raw_data=device_data,
        )
        
        return device

    async def async_control_device(
        self,
        device_id: str,
        property_identifier: str,
        value: Any,
    ) -> bool:
        """Control device by setting property value.
        
        Args:
            device_id: Target device ID
            property_identifier: Property to control
            value: Value to set
            
        Returns:
            True if control successful
            
        Raises:
            HeimanApiError: If control request fails
        """
        await self._ensure_authenticated()
        
        endpoint = "/api-app/device/control"
        
        request_data = {
            "deviceId": device_id,
            "commands": [
                {
                    "identifier": property_identifier,
                    "value": value,
                }
            ],
        }
        
        result = await self.http_client.post(endpoint, data=request_data)
        
        success = result.get("success", False)
        if not success:
            raise HeimanApiError(
                message=result.get("message", "Device control failed"),
                raw_response=result,
            )
        
        _LOGGER.debug(f"Successfully controlled device {device_id}")
        return True

    async def async_get_device_properties(
        self,
        device_id: str,
    ) -> dict[str, Any]:
        """Get current properties of a device.
        
        Args:
            device_id: Device ID
            
        Returns:
            Dictionary of property identifier to value
            
        Raises:
            HeimanApiError: If request fails
        """
        await self._ensure_authenticated()
        
        endpoint = "/api-app/device/get/properties"
        
        request_data = {
            "deviceId": device_id,
            "propertyIdentifiers": [],  # Empty means all properties
        }
        
        result = await self.http_client.post(endpoint, data=request_data)
        
        properties_data = result.get("data", [])
        properties = {}
        
        for prop_data in properties_data:
            identifier = prop_data.get("identifier", "")
            value = prop_data.get("value")
            properties[identifier] = value
        
        return properties

    async def close(self) -> None:
        """Close the client."""
        await self.http_client.close()


# Import here to avoid circular imports
from .models import DeviceProperty
