import json

from typing import List, Dict

from mbcontextmessagehandler import MbContextMessageBus
from mwhelper import BaseRepository
from persistence import Connection

from model.error_type import PosValidationErrorsType
from model.exception import ValidationError
from model.payment import PaymentType
from model.services import PaymentServiceModel


class PaymentService(PaymentServiceModel, BaseRepository):

    def __init__(
            self,
            message_bus     # type: MbContextMessageBus
    ):
        # type: (...) -> None

        super(PaymentService, self).__init__(message_bus.mbcontext)
        self.message_bus = message_bus
        self.payment_types = None

    def get_payment_types(
        self
    ):
        # type: () -> List[PaymentType]

        def inner_func(conn):
            # type: (Connection) -> List[int]

            query = """
                SELECT
                    TT.TenderId AS TenderId,
                    TT.TenderDescr AS TenderDescr,
                    TT.ElectronicType AS ElectronicTypeId,
                    TET.TypeDescr AS ElectronicTypeDescr,
                    TT.ParentTenderId AS ParentTenderId,
                    TT.CustomAttr As CustomAttr
                FROM productdb.TenderType TT
                JOIN productdb.TenderElectronicType TET ON TET.TypeId=TT.ElectronicType;
            """
            cursor = conn.select(query)

            tenders = {}
            for row in cursor:
                tender_id = int(row.get_entry('TenderId'))
                parent_tender_id = row.get_entry('ParentTenderId')
                tenders[tender_id] = {
                    'id': tender_id,
                    'descr': row.get_entry('TenderDescr'),
                    'electronicType': row.get_entry('ElectronicTypeDescr'),
                    'electronicTypeId': int(row.get_entry('ElectronicTypeId')),
                    'parentId ': int(parent_tender_id) if parent_tender_id else None,
                    'customAttr': row.get_entry('CustomAttr')
                }

            return tenders

        if not self.payment_types:
            self.payment_types = self.format_payment_types(self.execute_with_connection(
                inner_func,
                service_name="Persistence"
            ))

        return self.payment_types

    def format_payment_types(
            self,
            tender_types    # type: List[Dict[int, str]]
    ):
        # type: (...) -> List[PaymentType]

        payment_types = []

        for index, tender in tender_types.items():
            if "customAttr" not in tender or index >= 90:
                continue

            custom_attr = json.loads(tender["customAttr"] or "{}")
            show = custom_attr["showInTotem"] if "showInTotem" in custom_attr else False
            if not show:
                continue

            image_path = custom_attr["imagePath"] if "imagePath" in custom_attr else None
            payment_type = PaymentType(
                name=tender["descr"],
                payment_type=index,
                image_path=image_path
            )

            payment_types.append(payment_type)

        if not payment_types:
            raise ValidationError(PosValidationErrorsType.PaymentTypesToShowNotFound)

        return sorted(payment_types, key=lambda p: p.payment_type)
