from ..core import Provider
from ..core import Response
from ..utils import requests
from ..utils.helpers import snake_to_camel_case


class Twilio(Provider):
    """Send an SMS via a Twilio number"""

    name = "twilio"
    base_url = "https://api.twilio.com/2010-04-01/Accounts/{}/Messages.json"
    site_url = "https://www.twilio.com/"
    path_to_errors = ("message",)

    _required = {
        "allOf": [
            {
                "anyOf": [
                    {"anyOf": [{"required": ["from"]}, {"required": ["from_"]}]},
                    {"required": ["messaging_service_id"]},
                ],
                "error_anyOf": "Either 'from' or 'messaging_service_id' are required",
            },
            {
                "anyOf": [{"required": ["message"]}, {"required": ["media_url"]}],
                "error_anyOf": "Either 'message' or 'media_url' are required",
            },
            {"required": ["to", "account_sid", "auth_token"]},
        ]
    }

    _schema = {
        "type": "object",
        "properties": {
            "message": {
                "type": "string",
                "title": "The text body of the message. Up to 1,600 characters long.",
                "maxLength": 1_600,
            },
            "account_sid": {
                "type": "string",
                "title": "The unique id of the Account that sent this message.",
            },
            "auth_token": {"type": "string", "title": "The user's auth token"},
            "to": {
                "type": "string",
                "format": "e164",
                "title": "The recipient of the message, in E.164 format",
            },
            "from": {
                "type": "string",
                "title": "Twilio phone number or the alphanumeric sender ID used",
            },
            "from_": {
                "type": "string",
                "title": "Twilio phone number or the alphanumeric sender ID used",
                "duplicate": True,
            },
            "messaging_service_id": {
                "type": "string",
                "title": "The unique id of the Messaging Service used with the message",
            },
            "media_url": {
                "type": "string",
                "format": "uri",
                "title": "The URL of the media you wish to send out with the message",
            },
            "status_callback": {
                "type": "string",
                "format": "uri",
                "title": "A URL where Twilio will POST each time your message status changes",
            },
            "application_sid": {
                "type": "string",
                "title": "Twilio will POST MessageSid as well as MessageStatus=sent or MessageStatus=failed to the URL "
                "in the MessageStatusCallback property of this Application",
            },
            "max_price": {
                "type": "number",
                "title": "The total maximum price up to the fourth decimal (0.0001) in US dollars acceptable for "
                "the message to be delivered",
            },
            "provide_feedback": {
                "type": "boolean",
                "title": "Set this value to true if you are sending messages that have a trackable user action and "
                "you intend to confirm delivery of the message using the Message Feedback API",
            },
            "validity_period": {
                "type": "integer",
                "title": "The number of seconds that the message can remain in a Twilio queue",
                "minimum": 1,
                "maximum": 14_400,
            },
        },
    }

    def _prepare_data(self, data: dict) -> dict:
        if data.get("message"):
            data["body"] = data.pop("message")
        new_data = {
            "auth_token": data.pop("auth_token"),
            "account_sid": data.pop("account_sid"),
        }
        for key in data:
            camel_case_key = snake_to_camel_case(key)
            new_data[camel_case_key] = data[key]
        return new_data

    def _send_notification(self, data: dict) -> Response:
        account_sid = data.pop("account_sid")
        url = self.base_url.format(account_sid)
        auth = (account_sid, data.pop("auth_token"))
        response, errors = requests.post(
            url, data=data, auth=auth, path_to_errors=self.path_to_errors
        )
        return self.create_response(data, response, errors)
