import requests
import xml.etree.ElementTree as ElementTree

from datetime import datetime
from ..util import Addr
from enum import Enum
from ..http import HTTPMethod
from typing import Union


class Error(Enum):
    ERROR_SYSTEM_NO_SUPPORT = 100002
    ERROR_SYSTEM_NO_RIGHTS = 100003
    ERROR_SYSTEM_BUSY = 100004
    ERROR_LOGIN_USERNAME_WRONG = 108001
    ERROR_LOGIN_PASSWORD_WRONG = 108002
    ERROR_LOGIN_ALREADY_LOGIN = 108003
    ERROR_LOGIN_USERNAME_PWD_WRONG = 108006
    ERROR_LOGIN_USERNAME_PWD_ORERRUN = 108007
    ERROR_LOGIN_TOUCH_ALREADY_LOGIN = 108009
    ERROR_VOICE_BUSY = 120001
    ERROR_WRONG_TOKEN = 125001
    ERROR_WRONG_SESSION = 125002
    ERROR_WRONG_SESSION_TOKEN = 125003


class WifiStatus(Enum):
    WIFI_CONNECTING = '900'
    WIFI_CONNECTED = '901'
    WIFI_DISCONNECTED = '902'
    WIFI_DISCONNECTING = '903'


class Cradle(Enum):
    CRADLE_CONNECTING = '900'
    CRADLE_CONNECTED = '901'
    CRADLE_DISCONNECTED = '902'
    CRADLE_DISCONNECTING = '903'
    CRADLE_CONNECTFAILED = '904'
    CRADLE_CONNECTSTATUSNULL = '905'
    CRANDLE_CONNECTSTATUSERRO = '906'


class MacroEVDOLevel(Enum):
    MACRO_EVDO_LEVEL_ZERO = '0'
    MACRO_EVDO_LEVEL_ONE = '1'
    MACRO_EVDO_LEVEL_TWO = '2'
    MACRO_EVDO_LEVEL_THREE = '3'
    MACRO_EVDO_LEVEL_FOUR = '4'
    MACRO_EVDO_LEVEL_FIVE = '5'


class MacroNetWorkType(Enum):
    MACRO_NET_WORK_TYPE_NOSERVICE = 0
    MACRO_NET_WORK_TYPE_GSM = 1
    MACRO_NET_WORK_TYPE_GPRS = 2
    MACRO_NET_WORK_TYPE_EDGE = 3
    MACRO_NET_WORK_TYPE_WCDMA = 4
    MACRO_NET_WORK_TYPE_HSDPA = 5
    MACRO_NET_WORK_TYPE_HSUPA = 6
    MACRO_NET_WORK_TYPE_HSPA = 7
    MACRO_NET_WORK_TYPE_TDSCDMA = 8
    MACRO_NET_WORK_TYPE_HSPA_PLUS = 9
    MACRO_NET_WORK_TYPE_EVDO_REV_0 = 10
    MACRO_NET_WORK_TYPE_EVDO_REV_A = 11
    MACRO_NET_WORK_TYPE_EVDO_REV_B = 12
    MACRO_NET_WORK_TYPE_1xRTT = 13
    MACRO_NET_WORK_TYPE_UMB = 14
    MACRO_NET_WORK_TYPE_1xEVDV = 15
    MACRO_NET_WORK_TYPE_3xRTT = 16
    MACRO_NET_WORK_TYPE_HSPA_PLUS_64QAM = 17
    MACRO_NET_WORK_TYPE_HSPA_PLUS_MIMO = 18
    MACRO_NET_WORK_TYPE_LTE = 19
    MACRO_NET_WORK_TYPE_EX_NOSERVICE = 0
    MACRO_NET_WORK_TYPE_EX_GSM = 1
    MACRO_NET_WORK_TYPE_EX_GPRS = 2
    MACRO_NET_WORK_TYPE_EX_EDGE = 3
    MACRO_NET_WORK_TYPE_EX_IS95A = 21
    MACRO_NET_WORK_TYPE_EX_IS95B = 22
    MACRO_NET_WORK_TYPE_EX_CDMA_1x = 23
    MACRO_NET_WORK_TYPE_EX_EVDO_REV_0 = 24
    MACRO_NET_WORK_TYPE_EX_EVDO_REV_A = 25
    MACRO_NET_WORK_TYPE_EX_EVDO_REV_B = 26
    MACRO_NET_WORK_TYPE_EX_HYBRID_CDMA_1x = 27
    MACRO_NET_WORK_TYPE_EX_HYBRID_EVDO_REV_0 = 28
    MACRO_NET_WORK_TYPE_EX_HYBRID_EVDO_REV_A = 29
    MACRO_NET_WORK_TYPE_EX_HYBRID_EVDO_REV_B = 30
    MACRO_NET_WORK_TYPE_EX_EHRPD_REL_0 = 31
    MACRO_NET_WORK_TYPE_EX_EHRPD_REL_A = 32
    MACRO_NET_WORK_TYPE_EX_EHRPD_REL_B = 33
    MACRO_NET_WORK_TYPE_EX_HYBRID_EHRPD_REL_0 = 34
    MACRO_NET_WORK_TYPE_EX_HYBRID_EHRPD_REL_A = 35
    MACRO_NET_WORK_TYPE_EX_HYBRID_EHRPD_REL_B = 36
    MACRO_NET_WORK_TYPE_EX_WCDMA = 41
    MACRO_NET_WORK_TYPE_EX_HSDPA = 42
    MACRO_NET_WORK_TYPE_EX_HSUPA = 43
    MACRO_NET_WORK_TYPE_EX_HSPA = 44
    MACRO_NET_WORK_TYPE_EX_HSPA_PLUS = 45
    MACRO_NET_WORK_TYPE_EX_DC_HSPA_PLUS = 46
    MACRO_NET_WORK_TYPE_EX_TD_SCDMA = 61
    MACRO_NET_WORK_TYPE_EX_TD_HSDPA = 62
    MACRO_NET_WORK_TYPE_EX_TD_HSUPA = 63
    MACRO_NET_WORK_TYPE_EX_TD_HSPA = 64
    MACRO_NET_WORK_TYPE_EX_TD_HSPA_PLUS = 65
    MACRO_NET_WORK_TYPE_EX_802_16E = 81
    MACRO_NET_WORK_TYPE_EX_LTE = 101


def post_data_to_xml(data: dict, depth: int = 1) -> str:
    if depth == 1:
        return '<?xml version: "1.0" encoding="UTF-8"?>'+post_data_to_xml({'request': data}, depth+1)

    items = []
    for k, v in data.items():
        if isinstance(v, dict):
            v = post_data_to_xml(v, depth+1)
        elif isinstance(v, list):
            raise TypeError('list type is unsupported here')
        items.append(f'<{k}>{v}</{k}>')

    return ''.join(items)


class E3372:
    _addr: Addr
    _need_auth: bool
    _legacy_token_auth: bool
    _get_raw_data: bool
    _headers: dict[str, str]
    _authorized: bool

    def __init__(self,
                 addr: Addr,
                 need_auth: bool = True,
                 legacy_token_auth: bool = False,
                 get_raw_data: bool = False):
        self._addr = addr
        self._need_auth = need_auth
        self._legacy_token_auth = legacy_token_auth
        self._get_raw_data = get_raw_data
        self._authorized = False
        self._headers = {}

    @property
    def device_information(self):
        self.auth()
        return self.request('device/information')

    @property
    def device_signal(self):
        self.auth()
        return self.request('device/signal')

    @property
    def monitoring_status(self):
        self.auth()
        return self.request('monitoring/status')

    @property
    def notifications(self):
        self.auth()
        return self.request('monitoring/check-notifications')

    @property
    def dialup_connection(self):
        self.auth()
        return self.request('dialup/connection')

    @property
    def traffic_stats(self):
        self.auth()
        return self.request('monitoring/traffic-statistics')

    @property
    def sms_count(self):
        self.auth()
        return self.request('sms/sms-count')

    def sms_send(self, phone: str, text: str):
        self.auth()
        return self.request('sms/send-sms', HTTPMethod.POST, {
            'Index': -1,
            'Phones': {
                'Phone': phone
            },
            'Sca': '',
            'Content': text,
            'Length': -1,
            'Reserved': 1,
            'Date': -1
        })

    def sms_list(self, page: int = 1, count: int = 20, outbox: bool = False):
        self.auth()
        xml = self.request('sms/sms-list', HTTPMethod.POST, {
            'PageIndex': page,
            'ReadCount': count,
            'BoxType': 1 if not outbox else 2,
            'SortType': 0,
            'Ascending': 0,
            'UnreadPreferred': 1 if not outbox else 0
        }, return_body=True)

        root = ElementTree.fromstring(xml)
        messages = []
        for message_elem in root.find('Messages').findall('Message'):
            message_dict = {child.tag: child.text for child in message_elem}
            message_dict['UnixTime'] = int(datetime.strptime(message_dict['Date'], '%Y-%m-%d %H:%M:%S').timestamp())
            messages.append(message_dict)
        return messages

    def auth(self):
        if self._authorized:
            return

        if not self._legacy_token_auth:
            data = self.request('webserver/SesTokInfo')
            self._headers = {
                'Cookie': data['SesInfo'],
                '__RequestVerificationToken': data['TokInfo'],
                'Content-Type': 'text/xml'
            }
        else:
            data = self.request('webserver/token')
            self._headers = {
                '__RequestVerificationToken': data['token'],
                'Content-Type': 'text/xml'
            }

        self._authorized = True

    def request(self,
                method: str,
                http_method: HTTPMethod = HTTPMethod.GET,
                data: dict = {},
                return_body: bool = False) -> Union[str, dict]:
        url = f'http://{self._addr}/api/{method}'
        if http_method == HTTPMethod.POST:
            data = post_data_to_xml(data)
            f = requests.post
        else:
            data = None
            f = requests.get
        r = f(url, data=data, headers=self._headers)
        r.raise_for_status()
        r.encoding = 'utf-8'

        if return_body:
            return r.text

        root = ElementTree.fromstring(r.text)
        data_dict = {}
        for elem in root:
            data_dict[elem.tag] = elem.text
        return data_dict
