import datetime
import logging

from parsons import Table
from parsons.utilities import check_env
from parsons.utilities.api_connector import APIConnector

logger = logging.getLogger(__name__)

URI = "https://donorbox.org/api/v1"


class Donorbox(object):
    """
    Instantiate Donorbox class.

       `Args:`
            donorbox_account_email: str
                The email associated with your Donorbox account. Can be passed as
                argument or set as ``DONORBOX_ACCOUNT_EMAIL`` environment variable.
            donorbox_api_key: str
                The API key generated by Donorbox for your account. Can be passed as
                argument or set as ``DONORBOX_API_KEY`` environment variable.
    """

    def __init__(self, email=None, api_key=None):
        self.email = check_env.check("DONORBOX_ACCOUNT_EMAIL", email)
        self.api_key = check_env.check("DONORBOX_API_KEY", api_key)
        self.uri = URI
        self.client = APIConnector(self.uri, auth=(self.email, self.api_key))

    def get_campaigns(self, **kwargs):
        """
        Get information on campaigns.

        `Args:`
            id: int or str
                Optional. The ID of the campaign to get. If both id and name are omitted, returns
                all campaigns.
            name: str
                Optional. The name of the campaign to get. If both id and name are omitted, retunrs
                all campaigns.
            order: str
                Optional. Valid values are "asc" and "desc". If not supplied, order is descending
                by default.
            page: int
                Optional. Donorbox supports pagination for larger results. Use the page to track
                your progress.
            per_page: int
                Optional. Results per page when using pagination. Default is 50, maximum is 100.

        `Returns`:
            Parsons Table
        """
        result = self.client.request("campaigns", "GET", params=kwargs)
        data = result.json()
        return Table(data)

    def get_donations(self, **kwargs):
        """
        Get information on donations.

        `Args:`
            email: str
                Optional. Filter's donations by donor's email
            date_from: str
                |  Optional. Filters donations to those started on or after the provided date.
                |  Valid formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY
                |  If an incorrectly formatted date is provided, an error is raised.
            date_to: str
                |  Optional. Filters donations to those started before the provided date.
                |  Valid formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY
                |  If an incorrectly formatted date is provided, an error is raised.
            campaign_name: str
                Optional. Filters by the campaign title that you have defined in Donorbox.
            campaign_id: int or str
                Optional. Filters by Donorbox campaign id.
            donation_id: int or str
                Optional. Filters by Donorbox donations id.
            first_name: str
                Optional. Filters by donor's first name.
            last_name: str
                Optional. Filters by donor's last name.
            donor_id: int or str
                Optional. Filters by Donorbox donor id.
            amount_min: int or str
                Optional. Gets all donations above the provided minimum.
            amount_max: int or str
                Optional. Gets all donations below the provided maximum.
            order: str
                Optional. Valid values are "asc" and "desc". If not supplied, order is
                descending by default.
            page: int
                Optional. Donorbox supports pagination for larger results. Use the page
                to track your progress.
            per_page: int
                Optional. Results per page when using pagination. Default is 50, maximum
                is 100.

        `Returns`:
            Parsons Table
        """
        # switch variable names
        if "amount_max" in kwargs:
            kwargs["amount[usd][max]"] = kwargs.pop("amount_max")
        if "amount_min" in kwargs:
            kwargs["amount[usd][min]"] = kwargs.pop("amount_min")
        if "donation_id" in kwargs:
            kwargs["id"] = kwargs.pop("donation_id")
        self._check_date_helper(kwargs)
        data = self.client.get_request("donations", params=kwargs)
        return Table(data)

    def get_donors(self, **kwargs):
        """
        Get information on donors.

        `Args:`

            donor_id: str or int
                Optional. Filters by donor ID.
            first_name: str
                Optional. Filters by donor's first name.
            last_name: str
                Optional. Filters by donor's last name.
            donor_name: str
                Optional. Filter by donor's full name
            email: str
                Optional. Filter's donations by donor's email
            order: str
                Optional. Valid values are "asc" and "desc". If not supplied, order is descending
                by default.
            page: int
                Optional. Donorbox supports pagination for larger results. Use the page to track
                your progress.
            per_page: int
                Optional. Results per page when using pagination. Default is 50, maximum is 100.

        `Returns`:
            Parsons Table
        """
        if "donor_id" in kwargs:
            kwargs["id"] = kwargs.pop("donor_id")  # switch to Donorbox's (less specific) name
        data = self.client.get_request("donors", params=kwargs)
        return Table(data)

    def get_plans(self, **kwargs):
        """
        Get information on plans.

        `Args:`

            email: str
                Optional. Filter's plans by donor's email address.
            date_from: str
                |  Optional. Filters plans to those started on or after the provided date.
                |  Valid formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY
                |  If an incorrectly formatted date is provided, an error is raised.
            date_to: str
                |  Optional. Filters plans to those started before the provided date.
                |  Valid formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY
                |  If an incorrectly formatted date is provided, an error is raised.
            campaign_id: int or str
                Optional. Filters by Donorbox campaign id.
            campaign_name: str
                Optional. Filters by the campaign title that you have defined in Donorbox.
            donor_id: str or int
                Optional. Filters by donor ID.
            first_name: str
                Optional. Filters by donor's first name.
            last_name: str
                Optional. Filters by donor's last name.
            donor_name: str
                Optional. Filter by donor's full name
            order: str
                Optional. Valid values are "asc" and "desc". If not supplied, order is descending
                by default.
            page: int
                Optional. Donorbox supports pagination for larger results. Use the page to track
                your progress.
            per_page: int
                Optional. Results per page when using pagination. Default is 50, maximum is 100.

        `Returns`:
            Parsons Table
        """
        self._check_date_helper(kwargs)
        data = self.client.get_request("plans", params=kwargs)
        return Table(data)

    def _check_date_helper(self, params):
        """Searches through params for a date parameter and if found, calls format helper.

        params: dictionary
            Required. Dictionary of parameters to be passed to endpoint.

        `Returns`: None

        """
        if "date_from" in params and params["date_from"] is not None:
            self._date_format_helper(params["date_from"])
        if "date_to" in params and params["date_to"] is not None:
            self._date_format_helper(params["date_to"])

    def _date_format_helper(self, date_string):
        """Checks date format and warns if invalid (internal)

        Valid formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY

        date_string: str
            Required. Date in a string format to be checked against Donorbox's valid options.

        `Returns`: None
        """
        valid_formats = ["%Y-%m-%d", "%d-%m-%Y", "%Y/%m/%d", "%Y%m%d"]
        for str_format in valid_formats:
            try:
                datetime.datetime.strptime(date_string, str_format)
                return
            except ValueError:
                continue
        raise ValueError(
            f"The date you supplied, {date_string}, is not a valid Donorbox format."
            "Try the following formats: YYYY-mm-dd YYYY/mm/dd YYYYmmdd dd-mm-YYYY"
        )
