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

import base64
import json
import logging

from xml.etree import cElementTree as eTree

import pyscripts

from peripherals.scale import PosScaleEvents
from typing import Tuple

from actions.eft import finish_eft_transactions
from application.interactor import (
    MessageDialogInteractor,
    MissingLogoutInfoInteractor,
)
from application.repository import PosCtrlRepository
from modelcommon.events import DialogEvent
from listeners import electronic_payment_listener
from sysactions import (
    get_model,
    get_podtype,
    get_posfunction,
    close_asynch_dialog,
    publish_event,
    show_any_dialog,
    update_any_dialog,
)

mbcontext = pyscripts.mbcontext
finger_print_reader_dlg_id = -1
last_sitef_status_update = {}

logger = logging.getLogger("PosActions")
pos_model_cache = {}


def _device_data_event_received(params):
    data, _, _, _, _ = params[:5]
    try:
        logger.info("Received device data: {0} ".format(data))

        xml = eTree.XML(data)
        device = xml.find("Device")
        device_name = str(device.get("name"))

        if device_name.startswith("scanner"):
            publish_scanner_event_to_ui(device, device_name)
        elif device_name.startswith("scale"):
            _get_weight(device_name, xml)
    except (Exception,):
        logger.exception('Exception processing device thread')


def publish_scanner_event_to_ui(device, device_name):
    pos_id = int(device_name[7:])
    barcode = base64.b64decode(device.text).strip('\0')

    event_subject = "POS{}".format(pos_id)
    publish_event(
        event_subject=event_subject,
        action_type="SCANNER_DATA",
        event_type="SCANNER",
        event_data=barcode,
    )


def _get_weight(device_name, xml):
    encoded_weight = xml.find("Device").text
    decoded_weight = base64.b64decode(encoded_weight)
    weight = float(decoded_weight)
    PosScaleEvents().add_weight(device_name, weight)


def event_order_modified_sitef(params):
    xml, _, event_type = params[:3]

    order = eTree.XML(xml).find(".//Order")
    if order is None:
        return

    pos_id = order.get("posId") or order.get("originatorId")[3:]
    if pos_id not in pos_model_cache:
        pos_model_cache[pos_id] = get_model(pos_id)
    model = pos_model_cache[pos_id]

    if event_type == "PAID":
        from posactions import is_table_service
        pod_type = get_podtype(model)
        pos_function = get_posfunction(model)
        is_table_service = is_table_service(model, order_picture=order)
        if pod_type not in ("OT", "DL") and pos_function not in ("OT", "DL") and not is_table_service:
            from threading import Thread
            sitef_transactions_thread = Thread(target=finish_eft_transactions, args=(pos_id, order, "1"))
            sitef_transactions_thread.daemon = True
            sitef_transactions_thread.start()

    if event_type == "VOID_ORDER":
        from posactions import is_table_service
        pod_type = get_podtype(model)
        pos_function = get_posfunction(model)
        is_table_service = is_table_service(model, order_picture=order)
        if pod_type not in ("OT", "DL") and pos_function not in ("OT", "DL") and not is_table_service:
            from threading import Thread
            sitef_transactions_thread = Thread(target=finish_eft_transactions, args=(pos_id, order, "0"))
            sitef_transactions_thread.daemon = True
            sitef_transactions_thread.start()


def eft_status_update(params):
    message, pos_id = params[0].split(';')
    pos_id = str(int(pos_id))

    dialog_type = "messageDialog"
    title = "$INFORMATION"
    timeout = 60000

    if pos_id not in last_sitef_status_update or last_sitef_status_update[pos_id] is None:
        dialog_id = show_any_dialog(
            pos_id,
            dialog_type,
            message,
            title,
            "",
            "",
            "",
            timeout,
            "NOCONFIRM",
            "",
            "",
            "",
            None,
            True
        )
        last_sitef_status_update[pos_id] = dialog_id
    else:
        dialog_id = last_sitef_status_update[pos_id]
        last_sitef_status_update[pos_id] = dialog_id
        update_any_dialog(
            pos_id,
            dialog_id,
            dialog_type,
            message,
            title,
            "",
            "",
            "",
            timeout,
            "NOCONFIRM",
            "",
            "",
            "",
            None
        )


def eft_status_finish(params):
    pos_id = params[0].split(';')[0]
    pos_id = str(int(pos_id))

    if pos_id in last_sitef_status_update and last_sitef_status_update[pos_id] is not None:
        close_asynch_dialog(pos_id, last_sitef_status_update[pos_id])
        last_sitef_status_update[pos_id] = None

    electronic_payment_listener.close_dialogs(pos_id)

def wait_message_dialog(params):
    event_type = params[2]
    data = json.loads(params[0])
    dialog_interactor = MessageDialogInteractor()
    dialog_interactor.configure(data, event_type)
    dialog_interactor.wait_messages()


def event_missing_logout_info(
    event,  # type: Tuple[str]
):
    # type: (...) -> None

    event_data = event[0]
    event_xml = eTree.XML(event_data)
    business_period = event_xml.get("businessPeriod")

    logger.info("[MISSING_LOGOUT_INFO] triggered for business period: {}".format(business_period))

    pos_ctrl_repository = PosCtrlRepository(mb_context=mbcontext)
    interactor = MissingLogoutInfoInteractor(pos_ctrl_repository=pos_ctrl_repository)
    interactor.fill_missing_logout_info(business_period=business_period)

    logger.info("[MISSING_LOGOUT_INFO] finished")


#
# Main function (called by pyscripts)
#
def main():
    pyscripts.subscribe_event_listener("ORDER_MODIFIED", event_order_modified_sitef)
    pyscripts.subscribe_event_listener("SITEF_STATUS_UPDATE", eft_status_update)
    pyscripts.subscribe_event_listener("SITEF_STATUS_UPDATE_FINISHED", eft_status_finish)
    pyscripts.subscribe_event_listener("DEVICE_DATA", _device_data_event_received)
    pyscripts.subscribe_event_listener("MISSING_LOGOUT_INFO", event_missing_logout_info)
    electronic_payment_listener.init()
    pyscripts.subscribe_event_listener(DialogEvent.WAIT_MESSAGE_DIALOG, wait_message_dialog)
