class PATinderBot:
    MAX_NUMBER_OF_PHOTOS = 6

    def __init__(self):
        self._read_secrets_file()
        self._read_schools_file()
        self.headers = {
            'app_version': '3',
            'platform': 'ios'
        }

        self.user, self.tinder_token = self.tinder_login()
        self.analyze_photo_success_rate(self.user.get('photos', []))

    def run_tinder_bot(self):
        print('Tinder bot is running')

        for user in self._recommendations():

            if user is None:
                break

            action = self._like_or_nope(user)
            if action == 'like':
                match = self._like(user)
                if match:
                    status = 'match'
                else:
                    status = 'like'
            elif action == 'nope':
                status = 'nope'
                self._nope(user)

            if action == 'like':
                self._create_photo_cards(user, status)

        print('Tinder bot is finished')

    def _recommendations(self):
        h = self.headers
        h['X-Auth-Token'] = self.tinder_token
        r = requests.get('https://api.gotinder.com/user/recs', headers=h)
        if r.status_code == 401:
            raise Exception('HTTP Error 401 Unauthorized')
        elif r.status_code == 504:
            raise Exception('HTTP Error 504 Gateway timeout')

        if 'results' not in r.json():
            print(r.json())

        results = r.json().get('results')
        if results:
            for result in results:
                yield PATinderUser(result)

    def _like(self, user):
        print(' -> Like {} ({})'.format(user.name, user.id))
        try:
            u = 'https://api.gotinder.com/like/{}'.format(user.id)
            d = requests.get(u, headers=self.headers, timeout=0.7).json()
            return d.get('match')
        except KeyError:
            # Only raise key errors
            raise
        except:
            # Ignore all other errors
            pass

    def _nope(self, user):
        print(' -> Nope {} ({})'.format(user.name, user.id))
        try:
            u = 'https://api.gotinder.com/pass/{}'.format(user.id)
            requests.get(u, headers=self.headers, timeout=0.7).json()
        except KeyError:
            # Only raise key errors
            raise
        except:
            # Ignore all other errors
            pass

    def _like_or_nope(self, user):
        '''Determine the 'like action' for the given user: like, nope or no_action

        If there is at least one good school: like
        If not, if there is at least one unknown school: no_action
        If not: nope
        '''
        unknown_school = False
        for school in user.schools:
            school_id = school.get('id')
            if school_id in self.schools:
                if self.schools[school_id] == 1:
                    print('Approved school: {}'.format(school.get('name')))
                    return 'like'
            else:
                self._update_schools(school)
                unknown_school = True
        if unknown_school:
            return 'no_action'
        else:
            return 'nope'

    def _create_photo_cards(self, user, status):
        self.collageCreator = PACollageCreator()
        for photo_index, photo in enumerate(user.d['photos']):
            if photo_index < self.MAX_NUMBER_OF_PHOTOS:
                self.collageCreator.download_img(url=photo['url'])
        self.collageCreator.create_collage(user, status)

    def _read_secrets_file(self):
        secrets_file = self._get_secrets_file_name()
        with open(secrets_file) as f:
            self.secrets = json.loads(f.read())

    def _read_schools_file(self):
        self.schools = dict()
        schools_file = self._get_schools_file_name()
        if not os.path.isfile(schools_file):
            schools_template_file = 'schools_template.json'
            copyfile(schools_template_file, schools_file)

        self._clean_schools_file()
        with open(schools_file) as f:
            schools = json.loads(f.read())
            for school in schools:
                school_id = school.get('id')
                if school_id in self.schools:
                    print('School with id {} occurs multiple times in {}'.
                          format(school_id, schools_file))
                self.schools[school_id] = school.get('status')

    @staticmethod
    def _get_secrets_file_name():
        secrets_file = 'secrets.json'
        return os.path.join(PACommon.get_dir('json'), secrets_file)

    @staticmethod
    def _get_schools_file_name():
        schools_file = 'schools.json'
        return os.path.join(PACommon.get_dir('json'), schools_file)

    @staticmethod
    def get_facebook_auth_token_url():
        url = 'https://www.facebook.com/v2.6/dialog/oauth'
        params = {
            'api_key': '464891386855067',  # Tinder's App ID
            'redirect_uri': 'fbconnect://success',  # Tinder's whitelisted redirect URI
            'response_type': 'token',
            'scope': 'email,public_profile'
        }
        response = requests.get(url, params)
        return response.url

    def tinder_login(self) -> (dict, str):
        """
        Log in to Tinder using the Facebook oAuth token

        :return: (user's info dictionary, user's Tinder oAuth token)
        """
        h = self.headers
        h['content-type'] = 'application/json'
        url = 'https://api.gotinder.com/auth'
        params = {
            'facebook_id': self.secrets.get('FACEBOOK_ID'),
            'facebook_token': self.secrets.get('FACEBOOK_AUTH_TOKEN')
        }
        req = requests.post(
            url,
            headers=h,
            data=json.dumps(params)
        )

        if req.status_code == 401:
            print('401 Unauthorized: Could not get token with parameters {}'.format(params))
            sys.exit(0)

        result = req.json()
        user = result.get('user')
        tinder_token = result.get('token')
        return user, tinder_token

    @staticmethod
    def analyze_photo_success_rate(photos):
        """Analyze the photo success rates of the user"""
        print('*** Photo analysis ***\n')
        for photo in photos:
            url = photo.get('url')
            select_rate = photo.get('selectRate')
            success_rate = photo.get('successRate')
            print('{}: select rate = {}, success rate = {}'.format(url, select_rate, success_rate))
        print('\n')

    def _clean_schools_file(self):
        """Remove duplicate schools from the school list"""
        schools_file = self._get_schools_file_name()
        with open(schools_file) as f:
            schools = json.loads(f.read())

        unique_school_ids = []
        unique_schools = []
        for school in schools:
            school_id = school.get('id')
            if school_id not in unique_school_ids:
                unique_school_ids.append(school_id)
                unique_schools.append(school)

        unique_schools = sorted(unique_schools, key=lambda k: k['id'])
        unique_schools = sorted(unique_schools, key=lambda k: k['status'])

        with open(schools_file, 'w') as outfile:
            json.dump(unique_schools, outfile, indent=4)

    def _update_schools(self, school):
        schools_file = self._get_schools_file_name()
        print(' -> Adding school {} to {}'.format(school.get('name'), schools_file))
        with open(schools_file) as f:
            schools = json.loads(f.read())
        schools.append({'id': school.get('id'),
                        'name': school.get('name', None),
                        'status': 2})
        with open(schools_file, 'w') as outfile:
            json.dump(schools, outfile, indent=4)
 def _create_photo_cards(self, user, status):
     self.collageCreator = PACollageCreator()
     for photo_index, photo in enumerate(user.d['photos']):
         if photo_index < self.MAX_NUMBER_OF_PHOTOS:
             self.collageCreator.download_img(url=photo['url'])
     self.collageCreator.create_collage(user, status)