import json
import re

from ..compat import compat_urllib_request, compat_urllib_error
from ..errors import ClientError, ClientLoginError
from ..http import MultipartFormDataEncoder
from ..compatpatch import ClientCompatPatch


class AccountsEndpointsMixin(object):

    def login(self):
        """Login."""
        challenge_response = self._call_api(
            'si/fetch_headers/',
            params='',
            query={'challenge_type': 'signup', 'guid': self.generate_uuid(True)},
            return_response=True)
        cookie_info = challenge_response.info().get('Set-Cookie')
        mobj = re.search(r'csrftoken=(?P<csrf>[^;]+)', cookie_info)
        if not mobj:
            raise ClientError(
                'Unable to get csrf from login challenge.',
                error_response=self._read_response(challenge_response))
        csrf = mobj.group('csrf')

        login_params = {
            'device_id': self.device_id,
            'guid': self.uuid,
            'phone_id': self.phone_id,
            '_csrftoken': csrf,
            'username': self.username,
            'password': self.password,
            'login_attempt_count': '0',
        }

        try:
            login_response = self._call_api(
                'accounts/login/', params=login_params, return_response=True)
        except compat_urllib_error.HTTPError as e:
            error_response = e.read()
            if e.code == 400:
                raise ClientLoginError('Unable to login: %s' % e)
            raise ClientError(e.reason, e.code, error_response)

        if not self.csrftoken:
            raise ClientError(
                'Unable to get csrf from login.',
                error_response=self._read_response(login_response))

        login_json = json.loads(self._read_response(login_response))

        if not login_json.get('logged_in_user', {}).get('pk'):
            raise ClientLoginError('Unable to login.')

        if self.on_login:
            on_login_callback = self.on_login
            on_login_callback(self)

        # # Post-login calls in client
        # self.sync()
        # self.autocomplete_user_list()
        # self.feed_timeline()
        # self.ranked_recipients()
        # self.recent_recipients()
        # self.direct_v2_inbox()
        # self.news_inbox()
        # self.explore()

    def current_user(self):
        """Get current user info"""
        params = self.authenticated_params
        res = self._call_api('accounts/current_user/', params=params, query={'edit': 'true'})
        if self.auto_patch:
            ClientCompatPatch.user(res['user'], drop_incompat_keys=self.drop_incompat_keys)
        return res

    def edit_profile(self, first_name, biography, external_url, email, phone_number, gender):
        """
        Edit profile

        :param first_name:
        :param biography:
        :param external_url:
        :param email: Required.
        :param phone_number:
        :param gender: male: 1, female: 2, unspecified: 3
        :return:
        """
        if int(gender) not in [1, 2, 3]:
            raise ValueError('Invalid gender: %d' % int(gender))
        if not email:
            raise ValueError('Email is required.')

        params = {
            'username': self.authenticated_user_name,
            'gender': int(gender),
            'phone_number': phone_number or '',
            'first_name': first_name or '',
            'biography': biography or '',
            'external_url': external_url or '',
            'email': email,
        }
        params.update(self.authenticated_params)
        res = self._call_api('accounts/edit_profile/', params=params)
        if self.auto_patch:
            ClientCompatPatch.user(res.get('user'))
        return res

    def remove_profile_picture(self):
        """Remove profile picture"""
        res = self._call_api(
            'accounts/remove_profile_picture/', params=self.authenticated_params)
        if self.auto_patch:
            ClientCompatPatch.user(res['user'], drop_incompat_keys=self.drop_incompat_keys)
        return res

    def change_profile_picture(self, photo_data):
        """
        Change profile picture

        :param photo_data: byte string of image
        :return:
        """
        endpoint = 'accounts/change_profile_picture/'
        json_params = json.dumps(self.authenticated_params)
        hash_sig = self._generate_signature(json_params)
        fields = [
            ('ig_sig_key_version', self.key_version),
            ('signed_body', hash_sig + '.' + json_params)
        ]
        files = [
            ('profile_pic', 'profile_pic', 'application/octet-stream', photo_data)
        ]

        content_type, body = MultipartFormDataEncoder(self.uuid).encode(fields, files)

        headers = self.default_headers
        headers['Content-Type'] = content_type
        headers['Content-Length'] = len(body)

        req = compat_urllib_request.Request(self.api_url + endpoint, body, headers=headers)
        try:
            response = self.opener.open(req, timeout=self.timeout)
        except compat_urllib_error.HTTPError as e:
            error_msg = e.reason
            error_response = e.read()
            try:
                error_obj = json.loads(error_response)
                if error_obj.get('message'):
                    error_msg = '%s: %s' % (e.reason, error_obj['message'])
            except:
                # do nothing, prob can't parse json
                pass
            raise ClientError(error_msg, e.code, error_response)

        json_response = json.loads(self._read_response(response))

        if self.auto_patch:
            ClientCompatPatch.user(json_response['user'], drop_incompat_keys=self.drop_incompat_keys)

        return json_response

    def set_account_private(self):
        """Make account private"""
        res = self._call_api('accounts/set_private/', params=self.authenticated_params)
        if self.auto_patch:
            ClientCompatPatch.list_user(res['user'], drop_incompat_keys=self.drop_incompat_keys)
        return res

    def set_account_public(self):
        """Make account public"""""
        res = self._call_api('accounts/set_public/', params=self.authenticated_params)
        if self.auto_patch:
            ClientCompatPatch.list_user(res['user'], drop_incompat_keys=self.drop_incompat_keys)
        return res

    def logout(self):
        """Logout user"""
        params = {
            'phone_id': self.phone_id,
            '_csrftoken': self.csrftoken,
            'guid': self.uuid,
            'device_id': self.device_id,
            '_uuid': self.uuid
        }
        return self._call_api('accounts/logout/', params=params, unsigned=True)

@@ -8,18 +8,8 @@
 json
-%0Aimport re
 %0A%0Afr
@@ -509,24 +509,25 @@
 e=True)%0A
+%0A
         
 cookie_i
@@ -522,153 +522,29 @@
     
-cookie_info = challenge_response.info().get('Set-Cookie')%0A        mobj = re.search(r'csrftoken=(?P%3Ccsrf%3E%5B%5E;%5D+)', cookie_info)%0A        if not mobj
+if not self.csrftoken
 :%0A  
@@ -707,42 +707,8 @@
 se))
-%0A        csrf = mobj.group('csrf')
 %0A%0A  
@@ -867,20 +867,30 @@
 token': 
-csrf
+self.csrftoken
 ,%0A      

Fix login to use cookiejar instead