# services/SQS.py
import os
import logging
from typing import Optional, Dict, Any

import boto3
from botocore.exceptions import ClientError

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class SQS:
    def __init__(self, region_name: Optional[str] = None, environment: Optional[str] = None):
        """
        SQS helper service.
        :param region_name: AWS region (falls back to AWS_DEFAULT_REGION or 'us-east-1')
        :param environment: prefix for queue names (falls back to NODE_ENVIRONMENT or 'Test')
        """
        self.environment = environment or os.getenv("NODE_ENVIRONMENT", "Test")
        region = region_name or os.getenv("AWS_DEFAULT_REGION", "us-east-1")
        self.client = boto3.client("sqs", region_name=region)

    def _queue_name(self, queue: str) -> str:
        return f"{self.environment}-{queue}"

    def _get_queue_url(self, queue_name: str) -> Optional[str]:
        try:
            resp = self.client.get_queue_url(QueueName=queue_name)
            return resp.get("QueueUrl")
        except ClientError:
            logger.exception("Failed to get queue URL for %s", queue_name)
            return None

    def publish(
        self,
        queue: str,
        message: str,
        group: Optional[str] = None,
        delay: Optional[int] = 0,
        message_attributes: Optional[Dict[str, Dict[str, Any]]] = None,
    ) -> Optional[Dict[str, Any]]:
        """
        Publish a message to an SQS queue.

        :param queue: queue name suffix (will be prefixed with environment)
        :param message: message body
        :param group: MessageGroupId (for FIFO queues)
        :param delay: DelaySeconds (0-900)
        :param message_attributes: boto3-style message attributes
        :return: boto3 response dict or None on error
        """
        queue_name = self._queue_name(queue)
        try:
            queue_url = self._get_queue_url(queue_name)
            if not queue_url:
                logger.error("Could not obtain queue URL for %s", queue_name)
                return None
            send_params: Dict[str, Any] = {
                "QueueUrl": queue_url,
                "MessageBody": message,
                "DelaySeconds": int(delay or 0),
            }
            if message_attributes:
                send_params["MessageAttributes"] = message_attributes
            if group:
                # required for FIFO queues; also FIFO queue names must end with .fifo on AWS.
                send_params["MessageGroupId"] = group

            result = self.client.send_message(**send_params)
            logger.info("Sent message to %s; MessageId=%s", queue_name, result.get("MessageId"))
            return result

        except ClientError:
            logger.exception("error occurred while sending sqs message to %s", queue_name)
            return None
        except Exception:
            logger.exception("unexpected error occurred while sending sqs message to %s", queue_name)
            return None

    def remove(self, queue: str, receipt: str) -> Optional[Dict[str, Any]]:
        """
        Delete a message from SQS.

        :param queue: queue name suffix (prefixed with environment)
        :param receipt: ReceiptHandle from a received message
        :return: boto3 response dict or None on error
        """
        queue_name = self._queue_name(queue)
        try:
            queue_url = self._get_queue_url(queue_name)
            if not queue_url:
                logger.error("Could not obtain queue URL for %s", queue_name)
                return None

            delete_params = {
                "QueueUrl": queue_url,
                "ReceiptHandle": receipt,
            }
            result = self.client.delete_message(**delete_params)
            logger.info("Deleted message from %s", queue_name)
            return result

        except ClientError:
            logger.exception("error occurred while deleting sqs message from %s", queue_name)
            return None
        except Exception:
            logger.exception("unexpected error occurred while deleting sqs message from %s", queue_name)
            return None
