# encoding: utf-8

import json
import xml.etree.cElementTree as eTree

import sysactions
from typing import List, Any, Dict

from repository import SaleChallengeRepository, ProductRepository, OrderRepository
from .model import ProductSaleItem, OperatorSaleItem, SaleChallengeItem
from utils import get_store_id


class SaleChallengeReport(object):

    def __init__(self, sale_challenge_repository, product_repository, order_repository, operator_id):
        # type: (SaleChallengeRepository, ProductRepository, OrderRepository, str) -> None

        self.sale_challenge_repository = sale_challenge_repository
        self.product_repository = product_repository
        self.order_repository = order_repository
        self.store_id = get_store_id()
        self.operator_id = operator_id

    def get_operator_name(self):
        if self.operator_id and self.operator_id not in ["0", "", "None"]:
            return eTree.XML(sysactions.get_user_information(self.operator_id)).find(".//user").get("LongName")
        return None

    def get_sale_challenge(self, sale_challenge_id):
        # type: (int) -> SaleChallengeItem
        return self.sale_challenge_repository.get_sale_challenge(sale_challenge_id)

    def get_sales_items(self, sale_challenge):
        # type:(SaleChallengeItem) -> Any[List[OperatorSaleItem], List[ProductSaleItem]]

        if self.operator_id:
            return self._get_operator_sold_items(sale_challenge)
        return self._get_order_items_all_operators(sale_challenge)

    @staticmethod
    def _get_operators_names():
        # type: () -> Dict[str, str]

        operator_name = {}
        for user in eTree.XML(sysactions.get_user_information()).findall(".//user"):
            operator_name[user.get("UserId")] = user.get("LongName")
        return operator_name

    def _get_order_items_all_operators(self, sale_challenge):
        # type: (SaleChallengeItem) -> List[OperatorSaleItem]

        paid_orders = self.order_repository.get_paid_orders_by_business_period(sale_challenge.start_date,
                                                                               sale_challenge.end_date)
        order_items = {}
        for i, p in enumerate(paid_orders):
            if p:
                self.order_repository.get_quantity_items_by_operator(p, order_items, i)

        operators = self._get_operators_names()

        operator_sales = {}
        for operator_id, operator_name in operators.items():
            if operator_id not in order_items.keys():
                continue

            for product_code, product_quantity in order_items[operator_id].items():
                if int(product_code) not in sale_challenge.products:
                    continue

                if operator_id not in operator_sales:
                    operator_sales[operator_id] = OperatorSaleItem(operator_name, product_quantity)
                else:
                    operator_sales[operator_id].quantity += product_quantity

        return list(operator_sales.values())

    def _get_operator_sold_items(self, sale_challenge):
        # type: (SaleChallengeItem) -> List[ProductSaleItem]

        product_names = self.product_repository.get_items_names(sale_challenge.products)
        initial_date = sale_challenge.start_date.strftime("%Y-%m-%d %H:%M:%S.0")
        end_date = sale_challenge.end_date.strftime("%Y-%m-%d %H:%M:%S.0")

        product_items = json.loads(sysactions.generate_report("pmix_order_items", initial_date, end_date,
                                                        self.store_id, self.operator_id))

        sold_items = {}
        for order_item in product_items:
            product_code = order_item['pcode']
            if product_code not in sale_challenge.products:
                continue

            if product_code not in sold_items:
                product_name = product_names[product_code]
                sold_items[product_code] = ProductSaleItem(product_name, order_item['quantity'],
                                                      order_item['quantity'] * float(order_item["unit_price"]))
            else:
                sold_items[product_code].quantity += order_item['quantity']
                sold_items[product_code].total_price += order_item['quantity'] * float(order_item["unit_price"])

        return list(sold_items.values())
