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

from datetime import datetime

from msgbus import MBEasyContext
from old_helper import BaseRepository
from persistence import Connection
from systools import sys_log_error
from typing import List, Dict


class OrderRepository(BaseRepository):

    def __init__(self, mbcontext, pos_list):
        # type: (MBEasyContext, List[int]) -> None

        super(OrderRepository, self).__init__(mbcontext)
        self.pos_list = pos_list

    def get_quantity_items_by_operator(self, all_orders, all_order_items, pos_index):
        # type: (Dict[str, List], Dict[str, Dict], int) -> Dict[str, Dict]

        def inner_func(conn):
            # type: (Connection) -> Dict[str, Dict]

            query = self._OrderItemsQuery

            order_list = []
            for orders in all_orders.values():
                order_list += orders
            order_list = ','.join(map(str, order_list))
            query = query.format(order_list)

            try:
                order_items = {}
                cursor = conn.select(query)
                for row in cursor:
                    order_id = str(row.get_entry(4))
                    product_code = str(row.get_entry(0))
                    quantity = float(row.get_entry(1))
                    if order_id in order_items:
                        order_items[order_id].append((product_code, quantity))
                    else:
                        order_items[order_id] = [(product_code, quantity)]

                for operator_id, orders_ids in all_orders.items():
                    if operator_id not in all_order_items.keys():
                        all_order_items[operator_id] = {}
                    for order_id in orders_ids:
                        for order_tuple in order_items[str(order_id)]:
                            product_code = order_tuple[0]
                            quantity = order_tuple[1]

                            if quantity == 0:
                                continue

                            if product_code not in all_order_items[operator_id].keys():
                                all_order_items[operator_id][product_code] = quantity
                            else:
                                all_order_items[operator_id][product_code] += quantity
                return all_order_items
            except Exception as e:
                sys_log_error("get order error: %s" % str(e))
                return {}

        return self.execute_with_connection(inner_func, db_name=str(self.pos_list[pos_index]))

    def get_paid_orders_by_business_period(self, initial_date, end_date):
        # type: (datetime, datetime) -> List[Dict[str, List]]
        return self._get_paid_orders(initial_date, end_date)

    def _get_paid_orders(self, initial_date, end_date):
        # type: (datetime, datetime) -> List[Dict[str, List]]
        def inner_func(conn):
            # type: (Connection) -> List[Dict[str, List]]

            try:
                query = self._PaidOrderQuery
                date_format = "%Y%m%d"

                query = query.format(initial_date.strftime(date_format), end_date.strftime(date_format))

                all_orders = {}  # type: Dict[str, List]
                valid_orders = [( int(x.get_entry(0)), x.get_entry(1) ) for x in conn.select(query)]

                for order_tuple in valid_orders:
                    order_id = order_tuple[0]
                    session_id = order_tuple[1]
                    session_id = session_id[session_id.find("user=") + 5:] if "user=" in session_id else ""
                    operator_id = session_id[0:session_id.find(",") if "," in session_id else None]

                    if operator_id not in all_orders:
                        all_orders[operator_id] = [order_id]
                    else:
                        all_orders[operator_id].append(order_id)

                return [all_orders]
            except Exception as _:
                return [{}]

        return self.execute_parallel_in_all_databases_returning_flat_list(inner_func, self.pos_list)

    _PaidOrderQuery = \
    """
        select distinct o.OrderId, o.SessionId
        from Orders o
        inner join OrderTender ot
        on o.OrderId = ot.OrderId
        where o.BusinessPeriod >= '{0}' and o.BusinessPeriod <= '{1}' and o.StateId = 5
    """

    _OrderItemsQuery = """\
    SELECT * FROM (
    SELECT PartCode, SUM(OrderedQty) as SOMA, ItemId, PriceListId1, OrderId
        FROM
            (SELECT 
			t.PartCode,
			CASE WHEN t.DefaultQty IS NULL
				THEN t.OrderedQty 
				ELSE
					CASE WHEN t.OrderedQty IS NULL
						THEN t.DefaultQty 
					ELSE
						CASE WHEN t.DefaultQty > t.OrderedQty
						THEN 0
						ELSE t.OrderedQty - t.DefaultQty
						END
					END
				END AS OrderedQty,
			t.ItemId,
			t.OrderId,
			s.PriceListId1
			FROM OrderItem t
			JOIN OrderItem u ON t.OrderId = u.OrderId AND t.LineNumber = u.LineNumber
			JOIN Orders s ON t.OrderId = s.OrderId
			JOIN ProductKernelParams pkp ON pkp.ProductCode = t.PartCode
			WHERE s.StateId = 5
			    AND u.Level = '0' 
			    AND t.OrderId IN ({0})
			    AND pkp.ProductType <> 1
			    AND t.PartCode NOT IN (
			        SELECT ProductCode FROM ProductTags
                    WHERE LOWER(Tag) = 'cfh=true'
                    UNION
                    SELECT ProductCode FROM ProductCustomParams
                    WHERE LOWER(CustomParamId) = 'cfh' AND LOWER(CustomParamValue) = 'true'
			    )
			    AND COALESCE(t.OrderedQty, t.DefaultQty) > 0) T
    GROUP BY PartCode, ItemId, OrderId) where SOMA is not null
    """
