import httpx
import logging
from typing import Optional, Dict, Any

from core.config import settings

logger = logging.getLogger(__name__)


async def send_push_notification(
    push_token: str, title: str, body: str, data: Optional[Dict[str, Any]] = None
) -> bool:
    """
    Sends a push notification to a specific Expo push token.

    Args:
        push_token: The recipient's Expo push token.
        title: The title of the notification.
        body: The main message content of the notification.
        data: Optional dictionary containing extra data to send with the notification.

    Returns:
        True if the notification was sent successfully (according to Expo API), False otherwise.
    """
    if not push_token:
        logger.warning("Attempted to send notification but no push token provided.")
        return False

    message = {
        "to": push_token,
        "sound": "default",
        "title": title,
        "body": body,
        "priority": "high",
        "channelId": "default",
    }
    if data:
        message["data"] = data

    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                settings.EXPO_PUSH_API_URL,
                headers={
                    "Accept": "application/json",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                },
                json=message,
                timeout=10.0,
            )
            response.raise_for_status()  # Raise exception for 4xx/5xx responses

            response_data = response.json()
            logger.debug(f"Expo push API response: {response_data}")

            # Check for top-level errors first
            if "errors" in response_data:
                error_messages = [
                    err.get("message", "Unknown error")
                    for err in response_data["errors"]
                ]
                logger.error(
                    f"Expo API returned errors for {push_token[:10]}...: {'; '.join(error_messages)}"
                )
                return False

            # Check the status in the data field
            receipt = response_data.get("data")

            # if receipts is a list
            if receipt:
                status = receipt.get("status")

                if status == "ok":
                    logger.info(
                        f"Successfully sent push notification to token: {push_token[:10]}..."
                    )
                    return True
                else:
                    # Log details if the status is not 'ok'
                    error_details = receipt.get("details")
                    error_message = receipt.get("message")
                    logger.error(
                        f"Failed to send push notification to {push_token[:10]}... "
                        f"Expo status: {status}, Message: {error_message}, Details: {error_details}"
                    )
                    return False
            else:
                # Log if 'data' is missing, not a list, or an empty list
                logger.error(
                    f"Unexpected Expo API response format or empty 'data' field for {push_token[:10]}... "
                    f"Response: {response_data}"
                )
                return False

        except httpx.HTTPStatusError as e:
            logger.error(
                f"HTTP error sending push notification to {push_token[:10]}...: {e.response.status_code} - {e.response.text}"
            )
            return False
        except httpx.RequestError as e:
            logger.error(
                f"Network error sending push notification to {push_token[:10]}...: {e}"
            )
            return False
        except Exception as e:
            logger.exception(
                f"Unexpected error sending push notification to {push_token[:10]}...: {e}"
            )
            return False
