# encoding: utf-8

import json
from typing import List, Dict

from benefitsreport.commons import discount_in_all_items, check_item_in_action
from benefitsreport.model import OrderBenefit, OrderBenefitInfo
from old_helper import BaseRepository


class BenefitsOrderRepository(BaseRepository):

    def __init__(self, mb_context, pos_list):
        super(BenefitsOrderRepository, self).__init__(mb_context)

        self.pos_list = pos_list

    def get_orders_benefit_detailed(self, initial_date, end_date, operator_id, benefits):
        # type: (str, str, str, Dict) -> List[OrderBenefit]

        def inner_func(conn):

            query_operator = " and SessionId like '%user={0},%'".format(operator_id) if operator_id is not None else ""
            query = self._OrdersQuery.format(initial_date, end_date, query_operator)
            orders = []
            benefit_keys = [x.get("key") for x in benefits]
            for row in conn.select(query):
                benefit_list_json = json.loads(row.get_entry("BenefitList"))
                benefit_list = json.loads(benefit_list_json.get("benefitList", None))
                for benefit in benefit_list:
                    benefit_key = benefit.get("benefit").get("name")
                    if benefit_key not in benefit_keys:
                        continue
                    benefit_id = benefit.get("benefit").get("id")
                    benefit_applied = benefit.get("benefit_applied", False)
                    benefit_applied_id = benefit.get("benefit_key", None)
                    benefit_json = benefit.get("benefit", {})
                    benefit_applied = benefit_applied and "{0}_".format(benefit_id) in benefit_applied_id

                    if benefit_applied and self._check_item_to_add(benefit_json, row):
                        discount_items_values = benefit_list_json.get("discountItemValues", {})
                        orders.append(OrderBenefit(row, discount_items_values, OrderBenefitInfo.from_json(benefit)))

            return orders

        return self.execute_parallel_in_all_databases_returning_flat_list(inner_func, self.pos_list)

    def get_orders_benefit_consolidated(self, initial_date, end_date, operator_id):
        # type: (str, str, str) -> List[OrderBenefit]

        def inner_func(conn):
            query_operator = " and SessionId like '%user={0},%'".format(operator_id) if operator_id is not None else ""
            query = self._OrdersQueryConsolidated.format(initial_date, end_date, query_operator)
            orders = []
            for row in conn.select(query):
                benefit_list_json = json.loads(row.get_entry("BenefitList"))
                benefit_list = json.loads(benefit_list_json.get("benefitList", None))
                for benefit in benefit_list:
                    benefit_json = benefit.get("benefit", {})
                    benefit_applied = benefit.get("benefit_applied", False)
                    if benefit_applied and self._check_item_to_add(benefit_json, row):
                        discount_items_values = benefit_list_json.get("discountItemValues", {})
                        orders.append(OrderBenefit(row, discount_items_values, OrderBenefitInfo.from_json(benefit)))

            return orders

        return self.execute_parallel_in_all_databases_returning_flat_list(inner_func, self.pos_list)

    @staticmethod
    def _check_item_to_add(benefit, item):
        part_code = item.get_entry("PartCode")
        return discount_in_all_items(benefit) or check_item_in_action(benefit, part_code)

    _OrdersQuery = """
                    SELECT o.OrderId,
                           o.BusinessPeriod,
                           it.PartCode,
                           it.ItemId,
                           it.Level,
                           P.ProductName,
                            COALESCE(CASE WHEN it.DefaultQty IS NULL
                            THEN it.OrderedQty 
                            ELSE
                                CASE WHEN it.OrderedQty IS NULL
                                THEN it.DefaultQty 
                                ELSE
                                    CASE WHEN it.DefaultQty > it.OrderedQty
                                    THEN 0
                                    ELSE it.OrderedQty - it.DefaultQty
                                    END
                                END
                            END, 0)
                           AS OrderedQty,
                           it.LineNumber,
                           COALESCE(it.OverwrittenUnitPrice, op.DefaultUnitPrice, 0.0) as DefaultUnitPrice,
                           ocp.Value AS BenefitList,
                           oic.Key AS discountType,
                           oic.Value AS discountKey
                     FROM Orders o
                     INNER JOIN OrderCustomProperties ocp ON ocp.OrderId = o.OrderId AND ocp.Key = 'BENEFIT_LIST'
                     INNER JOIN OrderItem it ON o.OrderId = it.OrderId
                     INNER JOIN productdb.Product P ON  it.PartCode = P.ProductCode
                     INNER JOIN OrderItemCustomProperties oic
                        ON o.OrderId = oic.OrderId
                       AND it.PartCode = oic.PartCode
                       AND it.LineNumber = oic.LineNumber
                       AND (oic.Key = 'benefitKey' OR oic.Key ='servicePeriod')
                      LEFT JOIN OrderItem comboItem 
                        ON comboItem.OrderId = it.OrderId 
                       AND comboItem.LineNumber = it.LineNumber 
                       AND comboItem.ItemId = it.ItemId ||'.'||it.PartCode
                     INNER JOIN OrderPrice op 
                        ON op.OrderId = it.OrderId AND op.PriceKey = IFNULL(it.PriceKey,comboItem.PriceKey)
                     WHERE 
                        o.BusinessPeriod >= '{0}' 
                        AND o.BusinessPeriod <= '{1}' 
                        AND o.StateId = 5
                        {2}
                     GROUP by o.OrderId, o.BusinessPeriod, it.PartCode, oic.Value
                     ORDER BY o.OrderId, o.BusinessPeriod, P.ProductName
                  """

    _OrdersQueryConsolidated = """
                        SELECT o.OrderId,
                               o.BusinessPeriod,
                               it.PartCode,
                               it.ItemId,
                               it.Level,
                                '' as ProductName,
                                   COALESCE(
                                        CASE WHEN it.DefaultQty IS NULL
                                        THEN it.OrderedQty 
                                        ELSE
                                            CASE WHEN it.OrderedQty IS NULL
                                                THEN it.DefaultQty 
                                            ELSE
                                                CASE WHEN it.DefaultQty > it.OrderedQty
                                                THEN 0
                                                ELSE it.OrderedQty - it.DefaultQty
                                                END
                                            END
                                        END
                                   , 0)
                                AS OrderedQty,
                               it.LineNumber,
                               COALESCE(it.OverwrittenUnitPrice, op.DefaultUnitPrice, 0.0) as DefaultUnitPrice,
                               ocp.Value as BenefitList,
                               oic.Key as discountType,
                               oic.Value as discountKey
                          FROM Orders o
                         INNER JOIN OrderCustomProperties ocp ON ocp.OrderId = o.OrderId AND ocp.Key = 'BENEFIT_LIST'
                         INNER JOIN OrderItem it ON o.OrderId = it.OrderId
                         INNER JOIN OrderItemCustomProperties oic ON o.OrderId = oic.OrderId
                           AND it.PartCode = oic.PartCode and it.LineNumber = oic.LineNumber
                           AND (oic.Key = 'benefitKey' or oic.Key ='servicePeriod')
                          LEFT JOIN OrderItem comboItem 
                            ON comboItem.OrderId = it.OrderId 
                           AND comboItem.LineNumber = it.LineNumber 
                           AND comboItem.ItemId = it.ItemId ||'.'||it.PartCode
                         INNER JOIN OrderPrice op 
                            ON op.OrderId = it.OrderId AND op.PriceKey = IFNULL(it.PriceKey,comboItem.PriceKey)
                         WHERE o.BusinessPeriod >= '{0}' and o.BusinessPeriod <= '{1}' AND o.StateId = 5
                            {2}
                         GROUP by o.OrderId, o.BusinessPeriod, it.PartCode, oic.Value
                         ORDER BY o.OrderId, o.BusinessPeriod
                      """
