from datetime import (
    date,
    datetime,
)
from typing import Optional
try:
    from xml.etree.cElementTree import Element
except ImportError:
    from xml.etree.ElementTree import Element

from ._PosUser import PosUser
from ._PosUserState import PosUserState
from ._UserControlType import UserControlType


class UserSession(object):
    def __init__(
        self,                   # type: UserSession
        user,                   # type: PosUser
        open_time,              # type: datetime
        pos_id,                 # type: int
        business_period,        # type: date
        login_count,            # type: int
        user_control_type,      # type: UserControlType
        initial_float=None,     # type: Optional[float]
        close_time=None,        # type: Optional[datetime]
        state=None,             # type: Optional[PosUserState]
    ):
        # type: (...) -> None

        self.user = user
        self.open_time = open_time
        self.initial_float = initial_float or 0.0
        self.close_time = close_time
        self.state = state or PosUserState.OPENED
        self.business_period = business_period
        self.user_control_type = user_control_type
        self.pos_id = pos_id
        self.login_count = login_count

    def to_xml(self):
        attrs = {
            "id": str(self.user.id),
            "name": self.user.name,
            "level": str(self.user.level),
            "state": self.state.name,
            "stateCode": str(self.state.value),
            "lastOpState": str(self.state.value),
            "initialFloat": str(self.initial_float),
            "openTime": self.open_time.strftime("%Y-%m-%d %H:%M:%S"),
            "period": self.business_period.strftime("%Y%m%d"),
            "userControlType": self.user_control_type.value,
            "posId": str(self.pos_id),
            "loginCount": str(self.login_count),
            "sessionId": self.get_session_id(),
        }
        if self.close_time is not None:
            attrs["closeTime"] = self.close_time.strftime("%Y-%m-%d %H:%M:%S")

        node = Element(
            "Operator",
            attrib=attrs,
        )

        return node

    def get_session_id(
        self,                   # type: UserSession
    ):
        period = self.business_period.strftime("%Y%m%d")
        session_id = "user={},count={},period={}".format(self.user.id, self.login_count, period)
        if self.user_control_type == UserControlType.SingleUser:
            session_id = "pos={},{}".format(self.pos_id, session_id)

        return session_id

    @classmethod
    def from_xml(cls, xml):
        close_time = xml.attrib.get("closeTime")
        if close_time is not None:
            close_time = datetime.strptime(close_time, "%Y-%m-%d %H:%M:%S")

        state_name = xml.attrib.get("state", "OPENED")
        state = PosUserState[state_name]

        period_str = xml.attrib.get("period", "0")
        if period_str == "0":
            business_period = date.today()
        else:
            business_period = date(
                year=int(period_str[0:4]),
                month=int(period_str[4:6]),
                day=int(period_str[6:8]),
            )

        usr_ctrl_type_str = xml.attrib.get("userControlType") or xml.attrib.get("usrCtrlType")
        user_control_type = UserControlType.SingleUser if not usr_ctrl_type_str else UserControlType(usr_ctrl_type_str)

        pos_id_str = xml.attrib.get("posId")
        pos_id = 0 if not pos_id_str else int(pos_id_str)

        login_count_str = xml.attrib.get("loginCount")
        login_count = int(login_count_str) if login_count_str else 1

        return cls(
            user=PosUser(
                id=int(xml.attrib["id"]),
                name=xml.attrib["name"],
                level=int(xml.attrib["level"]),
            ),
            open_time=datetime.strptime(xml.attrib["openTime"], "%Y-%m-%d %H:%M:%S"),
            pos_id=pos_id,
            business_period=business_period,
            user_control_type=user_control_type,
            initial_float=float(xml.attrib["initialFloat"]),
            close_time=close_time,
            state=state,
            login_count=login_count,
        )

    def __str__(self):
        return """UserSession(
            user={},
            open_time={},
            initial_float={},
            close_time={},
            state={},
            business_period={},
            user_control_type={},
            pos_id={},
            login_count={}
        )""".format(
            self.user,
            self.open_time,
            self.initial_float,
            self.close_time,
            self.state,
            self.business_period,
            self.user_control_type,
            self.pos_id,
            self.login_count,
        )

    def __repr__(self):
        return self.__str__()

    def __eq__(self, other):
        if not isinstance(other, UserSession):
            return False

        return self.__str__() == other.__str__()
