from .Service import APIService, DEFAULT_TIMEOUT_S, validate_phone
from schema import Schema, And, Optional, SchemaError


class SMSService(APIService):
    def __init__(self, username, api_key):
        super(SMSService, self).__init__(username, api_key)

    def _init_service(self):
        super(SMSService, self)._init_service()
        self._baseUrl = self._baseUrl + "/version1"
        if self._contentUrl:
            self._contentUrl = self._contentUrl + "/version1"

    def send(
        self,
        message,
        recipients,
        sender_id=None,
        enqueue=False,
        callback=None,
        timeout=DEFAULT_TIMEOUT_S,
    ):
        for phone in recipients:
            if not validate_phone(phone):
                raise ValueError("Invalid phone number: " + phone)

        url = self._make_url("/messaging")
        data = {
            "username": self._username,
            "to": ",".join(recipients),
            "message": message,
            "bulkSMSMode": 1,
        }

        if sender_id is not None:
            data["from"] = sender_id

        if enqueue:
            data["enqueue"] = 1

        return self._make_request(
            url,
            "POST",
            headers=self._headers,
            params=None,
            data=data,
            callback=callback,
            timeout=timeout,
        )

    def send_premium(
        self,
        message,
        short_code,
        recipients,
        keyword=None,
        link_id=None,
        retry_duration_in_hours=None,
        callback=None,
        timeout=DEFAULT_TIMEOUT_S,
    ):
        for phone in recipients:
            if not validate_phone(phone):
                raise ValueError("Invalid phone number: " + phone)

        url = self._make_url("/messaging", content=True)
        data = {
            "username": self._username,
            "to": ",".join(recipients),
            "from": short_code,
            "message": message,
            "bulkSMSMode": 0,
        }

        if link_id is not None:
            data["linkId"] = link_id

        if keyword is not None:
            data["keyword"] = keyword

        if retry_duration_in_hours is not None:
            data["retryDurationInHours"] = retry_duration_in_hours

        return self._make_request(
            url,
            "POST",
            headers=self._headers,
            params=None,
            data=data,
            callback=callback,
            timeout=timeout,
        )

    def fetch_messages(
        self, last_received_id=None, callback=None, timeout=DEFAULT_TIMEOUT_S
    ):
        url = self._make_url("/messaging")
        params = {"username": self._username}

        if last_received_id is not None:
            params["lastReceivedId"] = last_received_id

        return self._make_request(
            url,
            "GET",
            headers=self._headers,
            params=params,
            data=None,
            callback=callback,
            timeout=timeout,
        )

    def create_safaricom_subscription(
        self,
        short_code,
        keyword,
        phone_number=None,
        request_id=None,
        redirect_url=None,
        source_ip=None,
        user_agent=None,
        callback=None,
        timeout=DEFAULT_TIMEOUT_S,
    ):
        try:
            data = {
                "username": self._username,
                "shortCode": short_code,
                "keyword": keyword,
                "requestId": request_id,
                "redirectUrl": redirect_url,
                "sourceIp": source_ip,
                "userAgent": user_agent,
                "phoneNumber": phone_number,
            }
            for k, v in list(data.items()):
                if v is None:
                    del data[k]

            messageSchema = Schema(
                {
                    "username": And(str),
                    "shortCode": And(str),
                    "keyword": And(str),
                    "redirectUrl": And(str),
                    Optional("userAgent"): And(str),
                    Optional("sourceIp"): And(str),
                    Optional("phoneNumber"): And(
                        str,
                        lambda s: validate_phone(s),
                        error=f"Invalid phone number: {phone_number}",
                    ),
                    Optional("requestId"): And(str),
                }
            )
            data = messageSchema.validate(data)
        except SchemaError as err:
            raise ValueError(err)

        url = self._make_url("/subscription/safaricom", content=True)

        return self._make_request(
            url,
            "POST",
            headers=self._headers,
            data=data,
            params=None,
            callback=callback,
            timeout=timeout,
        )

    def send_hashed(
        self,
        message,
        masked_number,
        sender_id,
        telco="Safaricom",
        callback=None,
        timeout=DEFAULT_TIMEOUT_S,
    ):
        url = self._make_url("/messaging/bulk")
        data = {
            "username": self._username,
            "maskedNumber": masked_number,
            "telco": telco,
            "message": message,
            "senderId": sender_id,
            "phoneNumbers": [],
        }

        return self._make_request(
            url,
            "POST",
            headers=self._headers,
            params=None,
            data=data,
            callback=callback,
            timeout=timeout,
        )
