from pyticketswitch import utils
from pyticketswitch.cost_range import CostRange
from pyticketswitch.availability import AvailabilityDetails
from pyticketswitch.mixins import JSONMixin, PaginationMixin
from pyticketswitch.currency import CurrencyMeta


class Performance(JSONMixin, object):
    """Describes and occurance of an :class:`Event <pyticketswitch.event.Event>`.

    The performance will have either a **date_time** or a **name**.

    .. note:: The **date_time** field is a timezone aware datetime and it is
              localised for the venue and not the user.

    Attributes:
        id (str): identifier for the performance.
        event_id (str): identifier for the event.
        date_time (:obj:`datetime.datetime`): the localised date and time for
            the performance.
        date_description (str): a human readable description of the date of the
            performance.
        time_description (str): a human readable description of the time of the
            performance.
        has_pool_seats (bool): the performance has pool seats available.
        is_limited (bool): the performance has limited availability.
        cached_max_seats (int): This should not be used. Earlier versions of the documentation
            implied that it held a meaningful value for the availability, but this is not true,
            and the attribute was not always present. If you are using it then you should stop,
            and switch to cost range data instead if you still want cached availability data.
            For the time being the value will be one million instead of being absent entirely if the data is not available.
        cached_max_seats_is_real (bool): A boolean indicating whether the data in the previous variable
            is actually real or not. Can be used whilst migrating away from using it.
        cost_range (:class:`CostRange <pyticketswitch.cost_range.CostRange>`):
            pricing summary, may also include offers.
        no_singles_cost_range (:class:`CostRange <pyticketswitch.cost_range.CostRange>`):
            pricing summary when no leaving single seats, may also include
            offers.
        is_ghost (bool): the performance is a ghost performance and is nolonger
            available.
        name (str): the name of the performance.
        running_time (int): the number of minutes the performance is expected
            to run for.
        availability_details (:class:`AvailabilityDetails <pyticketswitch.availability.AvailabilityDetails>`):
            summerised availability data for the performance. This data is
            cached from previous availability calls and may not be accurate.

    """

    def __init__(self, id_, event_id, date_time=None,
                 date_description=None, time_description=None, has_pool_seats=False,
                 is_limited=False, cached_max_seats=None, cached_max_seats_is_real=None, cost_range=None,
                 no_singles_cost_range=None, is_ghost=False, name=None,
                 running_time=None, availability_details=None):

        self.id = id_
        self.event_id = event_id
        self.date_time = date_time
        self.date_description = date_description
        self.time_description = time_description
        self.has_pool_seats = has_pool_seats
        self.is_limited = is_limited
        self.cached_max_seats = cached_max_seats
        self.cached_max_seats_is_real = cached_max_seats_is_real
        self.cost_range = cost_range
        self.no_singles_cost_range = no_singles_cost_range
        self.is_ghost = is_ghost
        self.name = name
        self.running_time = running_time
        self.availability_details = availability_details

    @classmethod
    def from_api_data(cls, data):
        """Creates a new **Performance** object from API data from ticketswitch.

        Args:
            data (dict): the part of the response from a ticketswitch API call
                that concerns a performance.

        Returns:
            :class:`Performance <pyticketswitch.order.Performance>`: a new
            :class:`Performance <pyticketswitch.order.Performance>` object
            populated with the data from the api.

        """
        id_ = data.get('perf_id')
        event_id = data.get('event_id')

        date_time = data.get('iso8601_date_and_time')
        if date_time:
            date_time = utils.isostr_to_datetime(date_time)

        date_desc = data.get('date_desc')
        time_desc = data.get('time_desc')

        api_cost_range = data.get('cost_range', {})
        api_no_singles_cost_range = api_cost_range.get('no_singles_cost_range', {})
        cost_range = None
        no_singles_cost_range = None

        if api_cost_range:
            api_cost_range['singles'] = True
            cost_range = CostRange.from_api_data(api_cost_range)

        if api_no_singles_cost_range:
            api_no_singles_cost_range['singles'] = False
            no_singles_cost_range = CostRange.from_api_data(
                api_no_singles_cost_range)

        availability_details = AvailabilityDetails.from_api_data(
            data.get('avail_details', {}))

        kwargs = {
            'id_': id_,
            'event_id': event_id,
            'date_time': date_time,
            'date_description': date_desc,
            'time_description': time_desc,
            'running_time': data.get('running_time'),
            'name': data.get('perf_name'),
            'has_pool_seats': data.get('has_pool_seats', False),
            'is_limited': data.get('is_limited', False),
            'is_ghost': data.get('is_ghost', False),
            'cached_max_seats': data.get('cached_max_seats'),
            'cost_range': cost_range,
            'no_singles_cost_range': no_singles_cost_range,
            'availability_details': availability_details,
        }

        return cls(**kwargs)

    def __repr__(self):
        if self.date_time:
            return u'<Performance {}: {}>'.format(self.id, self.date_time.isoformat())
        return u'<Performance {}>'.format(self.id)


class PerformanceMeta(PaginationMixin, CurrencyMeta, object):
    """
    PerformanceMeta contains meta information about a list of
    :class:`Performances <pyticketswitch.performance.Performance>`.

    Attributes:
        auto_select (bool): indicates that the performance list will contain
            only one performance and this performance should be automatically
            selected for the customer. See :ref:`Events that don't need
            performance selection
            <events_that_dont_need_performance_selection>` for more
            information.
        has_names: (bool): indicates that the related performances have names
    """

    def __init__(self, auto_select=False, has_names=False, *args, **kwargs):
        self.auto_select = auto_select
        self.has_names = has_names
        super(PerformanceMeta, self).__init__(*args, **kwargs)

    @classmethod
    def from_api_data(cls, data):
        """Creates a new **PerformanceMeta** object from API data from ticketswitch.

        Args:
            data (dict): the part of the response from a ticketswitch API call
                that concerns some performance meta data.

        Returns:
            :class:`PerformanceMeta <pyticketswitch.order.PerformanceMeta>`: a
            new :class:`PerformanceMeta <pyticketswitch.order.PerformanceMeta>`
            object populated with the data from the api.

        """
        inst = super(PerformanceMeta, cls).from_api_data(data)
        inst.auto_select = data.get('autoselect_this_performance', False)
        inst.has_names = data.get('results', {}).get('has_perf_names', False)

        return inst
