import requests
import urlparse
import time

from models.airline import *
from models.airport import *
from models.flight_segment import FlightSegment

__author__ = "Nick Lee"
__copyright__ = "Copyright (C) 2015 Nick Lee"
__license__ = "MIT License"

BASE_API_URL = "http://partners.api.skyscanner.net"
DIRECTIONALITY_OUTBOUND = 'Outbound'
DIRECTIONALITY_INBOUND = 'Inbound'
CABIN_ECONOMY = 'economy',
CABIN_PREMIUM = 'premiumeconomy'
CABIN_BUSINESS = 'business'
CABIN_FIRST = 'first'


class SkyscannerClient:
    def __init__(self, api_key):
        self.api_key = api_key

    def init_search_session(
            self,
            country,
            currency,
            dep,
            dest,
            outdate,
            indate,
            cabin,
            adult_count=1,
            children_count=0,
            infant_count=0,
            locale='en-GB'
    ):
        '''
        :param country: ISO2 string
        :param currency: ISO string
        :param dep: departure IATA airport code
        :param dest: destination IATA airport code
        :param outdate: outbound date YYYY-MM-DD string
        :param indate: inbound date YYYY-MM-DD string
        :param cabin: use CABIN_ consts
        :param adult_count: int
        :param children_count: int
        :param infant_count: int
        :param locale: locale string
        :return:
        '''

        query = {
            "Content-Type": "application/x-www-form-urlencoded",
            "Accept": "application/json",
            "country": country,
            "currency": currency,
            "locale": locale,
            "locationSchema": "iata",
            "grouppricing": "false",
            "originplace": dep,
            "destinationplace": dest,
            "outbounddate": outdate,
            "inbounddate": indate,
            "adults": adult_count,
            "children": children_count,
            "infants": infant_count,
            "cabinclass": cabin}

        res = self.get_flight_routes(query)
        populate_airport_cache(res)
        populate_airline_cache(res)
        return res

    def get_flight_routes(self, query_data):
        '''

        :param query_data: Query Data object generated by init_search_session
        :return: flight routes object with airline / airport RNID indices
        '''
        tries = 0
        r = requests.post("{}/apiservices/pricing/v1.0/?apikey={}".format(BASE_API_URL, self.api_key),
                          data=query_data)
        try:
            results = requests.get('{}?apiKey={}'.format(r.headers['Location'], self.api_key)).json()
        except:
            results = dict()
            results['Status'] = "err"
        while results['Status'] != "UpdatesComplete" and tries < 30:
            try:
                results = requests.get(r.headers['Location'] + "?apiKey=" + self.api_key).json()
            except:
                results['Status'] = "err"
            tries += 1
            time.sleep(1)
        return results

    def get_flight_segments(self, itinerary):
        '''

        :param itinerary: Skyscanner itinerary response object
        :return: Flight segment grouping
        '''
        details = itinerary['BookingDetailsLink']
        r = requests.put(BASE_API_URL + details['Uri'] + "?apiKey=" + self.api_key,
                         data=urlparse.parse_qs("&" + details['Body']))
        if r.status_code == 201:
            results = requests.get(r.headers['Location'] + "?apiKey=" + self.api_key).json()
            segments = results['Segments']
            flight_group = []
            for s in segments:
                try:
                    if s['Directionality'] == DIRECTIONALITY_OUTBOUND:
                        fs = FlightSegment(s['ArrivalDateTime'], s['Carrier'], s['DepartureDateTime'],
                                           s['DestinationStation'], DIRECTIONALITY_OUTBOUND, s['Duration'],
                                           s['FlightNumber'],
                                           s['OperatingCarrier'], s['OriginStation'])
                        flight_group.append(fs)
                    else:
                        fs = FlightSegment(s['ArrivalDateTime'], s['Carrier'], s['DepartureDateTime'],
                                           s['DestinationStation'], DIRECTIONALITY_INBOUND, s['Duration'],
                                           s['FlightNumber'],
                                           s['OperatingCarrier'], s['OriginStation'])
                        flight_group.append(fs)
                except:
                    return False
            return flight_group

    def print_flight_segments(self, itinerary):
        '''
        :param itinerary: Skyscanner itinerary response object
        '''
        details = itinerary['BookingDetailsLink']
        r = requests.put('{}{}?apiKey={}'.format(BASE_API_URL, details['Uri'], self.api_key),
                         data=urlparse.parse_qs("&" + details['Body']))
        if r.status_code == 201:
            results = requests.get(r.headers['Location'] + "?apiKey=" + self.api_key).json()
            segments = results['Segments']
            for s in segments:
                try:
                    if s['Directionality'] == DIRECTIONALITY_OUTBOUND:
                        print "=> Flight", airline_cache[s['Carrier']].iataCode, s['FlightNumber'], "Lasting", s[
                            'Duration'], "minutes from", airport_cache[s['OriginStation']].iataCode, "to", \
                            airport_cache[
                                s['DestinationStation']].iataCode
                    else:
                        print "<= Flight", airline_cache[s['Carrier']].iataCode, s['FlightNumber'], "Lasting", s[
                            'Duration'], "minutes from", airport_cache[s['OriginStation']].iataCode, "to", \
                            airport_cache[
                                s['DestinationStation']].iataCode
                except:
                    print "\n"
                    return False
            return True

    def get_itinerary_cost(self, itinerary):
        '''

        :param itinerary: Skyscanner itinerary response object
        :return: Decimal price of itinerary; currency code is
        '''
        prices = itinerary['PricingOptions']
        price_sum = 0.0
        count = 0
        for i in prices:
            price_sum += i['Price']
            count += 1
        return round(price_sum / count, 2)

    def get_deeplink(self, itinerary):
        for p in itinerary['PricingOptions']:
            # print "Debug:" + p['DeeplinkUrl']
            return p['DeeplinkUrl']

    def get_itineraries(self, result_object):
        r = result_object['Itineraries']
        return r
