

import os
import json
import urllib

import requests as rq
import random as rd
import datetime as dt
import ipywidgets as wg

from IPython.display import display, Image

from requests.packages.urllib3.exceptions import InsecureRequestWarning
rq.packages.urllib3.disable_warnings(InsecureRequestWarning)


class Api_v1:
    """
    """

    def __init__(self,
                 interactive=False,
                 login=None,
                 path_secret='my_secret.txt',
                 update_token=False,
                 verbose=False
                 ):
        """
        """
        self._show_logo()

        self.interactive = interactive
        self.SG_LOGIN = login
        self.path_secret = os.path.join(os.path.expanduser('~'),
                                        path_secret)
        self.update_token = update_token
        self.verbose = verbose
        self.path_token = os.path.join(os.path.expanduser('~'),
                                       'my_token.txt')

        try:
            self._load_my_secret()
        except Exception:
            msg = 'Error extracting data from {}.\nThis file either does not exist or is not properly formatted.'
            msg = msg.format(self.path_secret)
            print(msg)
            self.create_sample_my_secret()
            return

        self.access_token_endpoint = self._get_uri()
        self.proxies = self._get_proxies()

        if not interactive:
            self.access_token = self._get_access_token()

        else:
            self.widget_input = self.create_widget_input()
            display(self.widget_input)

    def create_widget_input(self):
        """
        """
        login = wg.Text(description='Login :',
                        placeholder='your login',
                        value=self.SG_LOGIN,
                        layout=wg.Layout(width='400px'))
        pwd = wg.Password(description='Password : ',
                          placeholder='your password',
                          layout=wg.Layout(width='300px'))
        btn = wg.Button(description='Go',
                        layout=wg.Layout(width='100px'))
        status = wg.Text(value='Not logged',
                         disabled=True,
                         layout=wg.Layout(width='160px'))

        def _now():
            return dt.datetime.now().strftime('%H:%M:%S')

        def on_clicked(b):
            status.value = 'Last Logged: ' + _now()
            self.SG_LOGIN = login.value
            self.SG_PASSWORD = pwd.value
            self.access_token = self._get_access_token()

        btn.on_click(on_clicked)

        box = wg.HBox([login, pwd, btn, status], layout=wg.Layout(display='flex',
                                                                  justify_content='space-around',
                                                                  width='850px'))
        return box

    def _get_access_token(self):
        """
        """
        if not os.path.isfile(self.path_token) or self.update_token:
            return self._request_access_token()
        else:
            return self._load_access_token()

    def clear_secret_token(self):
        """
        """
        for path in [self.path_secret, self.path_token]:
            if os.path.isfile(path):
                os.remove(path)
                print('Deleted file {}'.format(path))

    @staticmethod
    def _mask_data(d):
        """
        """
        hidden = ''
        if len(d) > 0:
            hidden = '*' * rd.randint(5, 40)
        d = d[:1] + hidden + d[-1:]
        return d

    @staticmethod
    def _show_secret(k, v):
        """
        """
        if 'PASSWORD' in k or 'LOGIN' in k or 'PROXY' in k:
            return Api_v1._mask_data(v)
        return v

    @staticmethod
    def _show_token(t):
        """
        """
        n = 10
        n2 = int(n / 2)
        hidden = '*' * (len(t) - n)
        t = t[:n2] + hidden + t[-n2:]
        return t

    def _load_my_secret(self):
        """
        """
        with open(self.path_secret, 'r') as f:
            lines = f.readlines()
            lines = [e.replace(' ', '') for e in lines]
            lines = [e.split('\n')[0] for e in lines]
            lines = [e for e in lines if e != '']
            # exclude comments
            lines = [e for e in lines if not e.startswith('#')]

            if self.verbose:
                print('Variables in {}'.format(self.path_secret))
            for e in lines:
                k, v = e.split('=')
                if self.verbose:
                    print('{}={}'.format(k, self._show_secret(k, v)))
                setattr(self, k, v)

    def create_sample_my_secret(self):
        """
        """
        print('Sample file created. Contents:')
        here = os.path.dirname(os.path.abspath(__file__))
        path = os.path.join(here,
                            'sample',
                            'my_secret.txt')
        with open(path, 'r') as f:
            content = f.read()
            print('-' * 15)
            print(content)
            print('-' * 15)
        with open(self.path_secret, 'w') as f:
            f.write(content)
        print('Edit it with your own data.')

    def _load_access_token(self):
        """
        """
        with open(self.path_token, 'r') as f:
            access_token = f.read()
            if self.verbose:
                print('Access token {} loaded from file {}'.format(self._show_token(access_token),
                                                                   self.path_token))
        return access_token

    def _get_uri(self):
        """
        TBD
        """
        # external SG Connect v1
        url = 'https://login.sgmarkets.com/richclient/gettoken'
        if self.verbose:
            print('Token endpoint: {}'.format(url))
        return url

    def _get_proxies(self):
        """
        """
        try:
            rq.get('https://google.com')
            proxies = {}
        except:
            dic = {'login': self.PROXY_LOGIN,
                   'pwd': urllib.parse.quote(self.PROXY_PASSWORD),
                   'proxy_host': self.PROXY_HOST,
                   'proxy_port': self.PROXY_PORT}
            proxies = {
                'http': 'http://{login}:{pwd}@{proxy_host}:{proxy_port}'.format(**dic),
                'https': 'https://{login}:{pwd}@{proxy_host}:{proxy_port}'.format(**dic)
            }

        if self.verbose:
            proxies2 = {}
            if proxies:
                dic2 = {'login': self._mask_data(self.PROXY_LOGIN),
                        'pwd': self._mask_data(self.PROXY_PASSWORD),
                        'proxy_host': self._mask_data(self.PROXY_HOST),
                        'proxy_port': self._mask_data(self.PROXY_PORT)}
                proxies2 = {
                    'http': 'http://{login}:{pwd}@{proxy_host}:{proxy_port}'.format(**dic2),
                    'https': 'https://{login}:{pwd}@{proxy_host}:{proxy_port}'.format(**dic2)
                }
            print('proxies:', proxies2)
        return proxies

    def _request_access_token(self):
        """
        TBD
        """
        params = {'Login': self.SG_LOGIN,
                  'Password': self.SG_PASSWORD,
                  'Application': 'SGM'}
        headers = {'Content-type': 'application/json'}
        proxies = self._get_proxies()
        r = rq.post(self.access_token_endpoint,
                    headers=headers,
                    # params=params,
                    data=json.dumps(params),
                    proxies=self.proxies,
                    verify=False)
        r.raise_for_status()
        content = r.json()

        if self.verbose:
            print(content)

        if not content['Success']:
            if self.interactive:
                self.widget_input.children[3].value = 'Wrong login/pwd'
            else:
                print('Wrong login/pwd')
            return

        assert content['TokenValue'], 'No TokenValue returned by SG Connect'
        access_token = content['TokenValue']

        if self.verbose:
            print('Access token {} saved to file {}'.format(self._show_token(access_token),
                                                            self.path_token))
        with open(self.path_token, 'w') as f:
            f.write(access_token)

        return access_token

    def get(self, url, payload=None):
        """
        """
        if payload is None:
            payload = {}
        headers = {'RC-Auth': self.access_token}
        r = rq.get(url,
                headers=headers,
                params=payload,
                proxies=self.proxies)
        if r.status_code != 200:
            raise Exception('Error in API request: {}'.format(r.text))

        return r.json()

    def post(self, url, payload=None):
        """
        """

        headers = {'RC-Auth': self.access_token,
                   'Content-type': 'application/json'
                   }
        r = rq.post(url,
                    headers=headers,
                    json=payload,
                    proxies=self.proxies)
        if r.status_code != 200:
            raise Exception('Error in API request: {}'.format(r.text))

        return r.json()

    def _show_logo(self):
        """
        """
        url_image = 'https://gitlab.com/sgmarkets/sgmarkets-api-auth/raw/master/sgmarkets_api_auth/img/sg-sgmarkets-logo.png'
        display(Image(url=url_image, width=200))
