#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import annotations

import configparser
import os
import urllib.parse as parser
from collections import UserDict

import boto3
import requests
from aws_xray_sdk.core import xray_recorder as xray

from psi_logger import logger
from psi_secrets import SecretsManager
from iobot.utils import init_config

@xray.capture()
class IOBotClient(UserDict):
    """ Initialize a copy of iobot.IOBotClient() for use

    Parameters
    ----------
    log : logging.Logger()
        Traditional python logger

    boto_session : boto3.session.Session()
        Boto3 Session Object

    config : configparser.ConfigParser()
        Per https://docs.python.org/2.0/ref/function.html set config
        explicitly to None and evaluate how it should be set if no value
        is passed. See iobot.utils for more information.

    config_file: str
        Defaults to iobot.ini
        If config is not passed, we will attempt to load config from this file.

    >>> os.environ['STACK_NAME'] = 'iobots-stack'

    >>> testing.export_secret_arns(os.environ['STACK_NAME'])

    >>> client = IOBotClient(log, boto_session, config_file = "environments/unit.ini", config_namespace = 'Cloudability')
    """

    @xray.capture()
    @logger.log
    def __init__(self,
                 log = None,
                 boto_session: boto3.session.Session = None,
                 http_session: requests.Session = None,
                 config: configparser.ConfigParser = None,
                 config_file: str = "iobot.ini",
                 secrets_manager: SecretsManager = None,
                 config_namespace: str = '',
                 **kwargs) -> None:
        self.data: dict = {}
        super().__init__(**kwargs)

        self._log = log or logger._get_logger()
        self._boto_session = boto_session or boto3.session.Session()
        self._http_session = http_session or requests.Session() 

        self.client: dict = {
            'log': self._log,
            'boto_session': self._boto_session,
            'http_session': self._http_session,
            'secrets_manager': secrets_manager or SecretsManager(log=log, session=self._boto_session),
            'http_headers': kwargs.get('headers', {"Content-Type": "application/json"})
        }

        self.config = config or init_config(config_file=config_file, env=dict(os.environ))
        self._log.debug(self.config)
        self._log.debug(f'loaded config sections: {self.config.sections()}')
        self._log.debug(f'client config namespace: {config_namespace}')

        self._log.debug(f'client specific config: {config_namespace}{dict(self.config[config_namespace])}')
        self.client['token'] = self.client['secrets_manager'].GetToken(self.config[config_namespace].get('token_arn'))

    def __repr__(self) -> str:
        """Return a string representation of the object"""
        return f"IOBotClient()"

    @xray.capture()
    @logger.log
    def Clients(self):
        return self.client

    @xray.capture()
    @logger.log
    def GetToken(self):
        return self.client['token']

    @xray.capture()
    @logger.log
    def HttpHeaders(self):
        return self.client['http_headers']

    @xray.capture()
    @logger.log
    def URLEncode(self, params: dict = None, doseq: bool = False) -> str:
        return parser.urlencode(params, doseq=doseq)

    @xray.capture()
    @logger.log
    def log(self):
        return self.client['log']

    @xray.capture()
    @logger.log
    def GetConfig(self):
        return self.config
