# -*- coding: utf-8 -*-

import os
import json
from xml.etree import cElementTree as eTree

import cfgtools
from posot import OrderTaker
from sysactions import (
    show_messagebox,
    show_keyboard,
    StopAction,
)

import helper
from mw_helper import show_message_options_dialog
from typing import (
    Optional,
    Union
)

from api.order import get_order_service
from utilfunctions import (
    validate_document,
    update_custom_properties,
    get_custom_property_value,
    input_document_pinpad_dialog
)
from model.customexception import RequiredDocumentException
from order_api import OrderService
from order_api.dto import CustomProperty

document_required_value = None


def _get_order_loyalty_customer_attribute(
    pos_id,                 # type: str
    order_picture,          # type: eTree.Element
    attribute="document",   # type: Optional[str]
):
    # type: (...) -> str

    from actions.loyalty import get_table_loyalty_customer_attribute

    loyalty_info = order_picture.find(".//OrderProperty[@key='LOYALTY_CUSTOMER_INFO']")
    table_id = order_picture.find(".//OrderProperty[@key='TABLE_ID']")
    if loyalty_info is not None:
        return json.loads(loyalty_info.get('value')).get('customerInfo', {}).get('customer', {}).get(attribute, '')
    elif table_id is not None:
        return get_table_loyalty_customer_attribute(
            pos_id=pos_id,
            table_id=table_id.get('value'),
            attribute=attribute,
        )
    return ''


def _set_document_order_property(
    order_service,  # type: OrderService
    document,       # type: str
    order_id,       # type: str
):
    # type: (...) -> None

    order_properties_dict = update_custom_properties(customer_doc=document)
    if order_properties_dict:
        order_service.set_order_custom_properties(
            custom_properties=[
                CustomProperty(
                    key=key,
                    value=value,
                ) for key, value in order_properties_dict.items()
            ],
            order_id=int(order_id),
        )


def validate_required_document(
    pos_id,                         # type: str
    pos_ot,                         # type: OrderTaker
    order,                          # type: eTree.Element
    ask_document_pinpad=False,      # type: Optional[bool]
):
    # type: (...) -> Union[str, bool]

    total_order = float(order.get("totalGross")) + float(order.get("tip", 0))
    required_value = get_document_required_value()
    ask_for_doc = required_value > 0.0 and (total_order >= required_value)

    document = get_custom_property_value(
        pos_id=pos_id,
        custom_property='CUSTOMER_DOC',
        order_picture=order,
    )
    loyalty_document = _get_order_loyalty_customer_attribute(
        pos_id=pos_id,
        order_picture=order,
    )
    order_service = get_order_service(pos_id=pos_id)
    if str(loyalty_document) == document:
        buttons = "$CONFIRM|$INFORM_ANOTHER|$WITHOUT_DOCUMENT"
        message = "$CONFIRM_CPF_CNPJ|{0}".format(helper.format_cpf_cnpj(value=loyalty_document))
        resp = show_message_options_dialog(
            pos_id=pos_id,
            buttons=buttons,
            title="$CONFIRMATION",
            message=message,
        )
        if resp == 2 or resp is None:
            return False

        elif resp == 1:
            loyalty_document = get_customer_doc(
                pos_id=pos_id,
                pos_ot=pos_ot,
                ask_document_pinpad=ask_document_pinpad,
            )
        _set_document_order_property(
            order_service=order_service,
            document=loyalty_document,
            order_id=order.get("orderId"),
        )
        return True

    elif ask_for_doc and document is None:
        message = "$DOC_REQUIRED|%s" % "{0:.2f}".format(required_value)
        show_messagebox(pos_id, message, "$INFORMATION")

        document = get_customer_doc(
            pos_id=pos_id,
            pos_ot=pos_ot,
            required=True,
            ask_document_pinpad=ask_document_pinpad,
        )
        _set_document_order_property(
            order_service=order_service,
            document=document,
            order_id=order.get("orderId"),
        )
        return document

    return False


def get_customer_doc(
    pos_id,                      # type: str
    pos_ot=None,                 # type: Optional[OrderTaker]
    default_doc="",              # type: Optional[str]
    required=False,              # type: bool
    ask_document_pinpad=False,   # type: Optional[bool]
    stop_action=True,            # type: Optional[bool]
    show_cancel_button=True,     # type: Optional[bool]
):
    # type: (...) -> Optional[str]

    valid = False
    customer_doc = None
    while not valid:
        if ask_document_pinpad:
            customer_doc = input_document_pinpad_dialog(pos_id)

        if customer_doc is None:
            message = "$ONLY_NUMBERS"
            title = "$ENTER_CUSTOMER_DOCUMENT"
            previous_button = "|$PREVIOUS" if show_cancel_button else ""
            if required:
                buttons = "$OK" + previous_button
            else:
                buttons = "$OK|$NOT_INFORM" + previous_button

            customer_doc = show_keyboard(
                posid=pos_id,
                message=message,
                title=title,
                buttons=buttons,
                mask='CPF_CNPJ',
                numpad=True,
                defvalue=default_doc,
            )

        if customer_doc is None:
            if required:
                raise RequiredDocumentException()
            if stop_action:
                raise StopAction()
            return None

        if customer_doc in ("NOT_INFORM", "EMPTY_DOC") and not required:
            customer_doc = ""
            break

        valid = validate_document(customer_doc)
        if not valid:
            customer_doc = None
            show_messagebox(pos_id, "$INVALID_CPF_CNPJ")

    if pos_ot is not None:
        fill_additional_info(
            pos_ot=pos_ot,
            properties="CPF",
            value=customer_doc,
        )

    return customer_doc


def get_customer_phone_number(
    pos_id,                       # type: str
    required=False,               # type: bool
    stop_action=True,             # type: Optional[bool]
):
    # type: (...) -> Optional[str]

    customer_phone = None
    while True:

        message = "$ONLY_NUMBERS"
        customer_phone = show_keyboard(
            posid=pos_id,
            message=message,
            title="$ENTER_CLIENT_PHONE",
            buttons="$OK|$NOT_INFORM|$PREVIOUS",
            mask="PHONE_NUMBER",
            numpad=True,
        )

        if customer_phone in (None, "NOT_INFORM"):
            return _get_not_informed_customer_phone_input(
                customer_phone=customer_phone,
                required=required,
                stop_action=stop_action,
            )

        if customer_phone == "" and not required:
            break

        if len(customer_phone) not in (10, 11):
            customer_phone = None
            show_messagebox(
                posid=pos_id,
                message="$INVALID_CUSTOMER_PHONE",
            )
        else:
            break

        show_messagebox(
            posid=pos_id,
            message="$INVALID_CUSTOMER_PHONE",
        )

    return customer_phone


def _get_not_informed_customer_phone_input(
    customer_phone,     # type: Optional[str]
    required,           # type: bool
    stop_action,        # type: bool
):
    # type: (...) -> Optional[str]

    if required:
        raise RequiredDocumentException()

    if stop_action:
        raise StopAction()

    return customer_phone


def fill_additional_info(
        pos_ot,         # type: OrderTaker
        properties,     # type: str
        value           # type: str
):
    # type: (...) -> None

    if pos_ot.additionalInfo:
        pos_ot.additionalInfo += "|"
    else:
        pos_ot.additionalInfo = ""

    pos_ot.additionalInfo += "{0}={1}".format(properties, value)


def get_document_required_value():
    # type: (...) -> float

    global document_required_value

    if document_required_value is None:
        config = cfgtools.read(os.environ["LOADERCFG"])
        document_required_value = float(config.find_value("Customizations.DocumentRequiredValue") or 0)

    return document_required_value
