# -*- coding: UTF-8 -*-
import os
import time
from datetime import date
import logging
from pathlib import Path
from collections import OrderedDict
from PyQt5.QtWidgets import QMainWindow, QDesktopWidget, QLabel, QLineEdit
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt

from .commons.dialogs import QuickDialog
from .commons.dblogin import safe_reconnect
from .proxy import FastModel
from .constants import SCREENS
from .dialogs import (
    Help, ControlPanel, SearchSale, SearchParty, SearchProduct, Position,
    Comment, DialogPayment, DialogSalesman, DialogVoucher, DialogPrintInvoice,
    DialogGlobalDiscount, DialogPaymentTerm, DialogStock, DialogOrder,
    DialogForceAssign, DialogTaxes, DialogCancelInvoice, EditLine, DialogAgent,
    DialogConsumer, DialogManageTables, DialogTableMoneyCount, AdditionProduct,
    DialogGlobalDiscountTable, DeliveryPartySelected, DialogTableDeliveryParty,
    DialogTableSaleConsumer, SaleConsumerSelected, DialogChannel,
    DialogDeliveryParty, TipAmount, DeliveryAmount
)
from .constants import DIALOG_REPLY_YES

__all__ = ['FrontWindow', 'ClearUi']

parent = Path(__file__).parent

file_base_css = os.path.join(str(parent), 'css', 'base.css')
_DEFAULT_TIMEOUT = 60000  # on ms (100 minutes)
path_trans = os.path.join(os.path.abspath(
    os.path.dirname(__file__)), 'locale', 'i18n_es.qm')


class FrontWindow(QMainWindow):

    def __init__(self, connection, params, title=None, show_mode=None):
        super(FrontWindow, self).__init__()
        if not title:
            title = self.tr('APPLICATION')

        self._state = None
        self._keyStates = {}
        self.window().setWindowTitle(title)
        self.setObjectName('WinMain')
        self.conn = connection
        self._context = connection.context
        self.set_params(params)
        self.logger = logging.getLogger('app_logger')

        """
        We need get the size of screen (display)
        ---------------  -------------------
              name           width (px)
        ---------------  -------------------
        small screen     =< 1024
        medium screen    > 1024 and =< 1366
        large screen     > 1366
        """

        screen = QDesktopWidget().screenGeometry()
        self.setGeometry(0, 0, screen.width(), screen.height())
        self.screen_width = screen.width()
        self.screen_height = screen.height()
        self.screen_size = 'large'
        if self.screen_width <= 1024:
            self.screen_size = 'small'
        elif self.screen_width <= 1366:
            self.screen_size = 'medium'

        self.timeout = _DEFAULT_TIMEOUT
        self.set_stack_messages()

        self.setFocus()
        self.global_timer = 0
        print('Screen Size: > ', self.screen_size)
        _theme = params['theme'] if params.get('theme') else None
        self.profile_printer = params['profile_printer'] if params.get('profile_printer') else 'TM-P80'
        self.set_style(SCREENS[self.screen_size], _theme)
        self.label_color = 'gray'
        self.label_color_2 = ''
        if _theme == 'dark':
            self.label_color = 'light'
            self.label_color_2 = 'orange'
        self.window().showMaximized()

    def filter_cache(self, data, filter, target):
        res = []
        for d in data:
            for t in target:
                if t in d[filter]:
                    res.append(d)
        return res

    def get_geometry(self):
        screen = QDesktopWidget().screenGeometry()
        return screen.width(), screen.height()

    def set_statusbar(self, values):
        status_bar = self.statusBar()
        status_bar.setSizeGripEnabled(False)

        for k, v in values.items():
            _label = QLabel(v['name'] + ':')
            _label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            _label.setObjectName('label_status_bar')
            status_bar.addWidget(_label, 1)
            setattr(self, k, QLabel(str(v['value'])))
            _field_info = getattr(self, k)
            _field_info.setObjectName('field_status_bar')
            _field_info.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            status_bar.addWidget(_field_info)

    def set_style(self, file_css, theme_css=None):
        styles = []
        if theme_css:
            theme_css = os.path.join(str(parent), 'css', theme_css + '.css')
        for style in [theme_css or file_base_css, file_css]:
            with open(style, 'r') as infile:
                styles.append(infile.read())
        self.setStyleSheet(''.join(styles))

    def set_timeout(self):
        if self.active_timeout != 'True':
            return

        self.timeout = eval(self.timeout)
        if not self.timeout:
            self.timeout = _DEFAULT_TIMEOUT
        timer = QTimer(self)
        timer.timeout.connect(self.count_time)
        timer.start(1000)

    def count_time(self):
        self.global_timer += 1
        if self.global_timer > self.timeout:
            self.global_timer = 0
            safe_reconnect()

    def close(self):
        dialog = self.dialog('confirm_exit', response=True)
        response = dialog.exec_()
        if response == DIALOG_REPLY_YES:
            self.check_empty_sale()
            if self.active_weighing and self.reader_thread:
                self.reader_thread.onClose()
            super(MainWindow, self).close()

    def dialog(self, name, response=False):
        res = QuickDialog(
            parent=self,
            kind=self.stack_msg[name][0],
            string=self.stack_msg[name][1],
        )
        return res

    def set_params(self, values):
        for k, v in values.items():
            if v in ('False', 'True'):
                v = eval(v)
            setattr(self, k, v)

    def action_block(self):
        safe_reconnect(self)

    def dialog_password_accept(self):
        self.connection()

    def dialog_password_rejected(self):
        self.connection()

    def keyReleaseEvent(self, event):
        self._keyStates[event.key()] = False

    def set_stack_messages(self):
        messages = {
            'system_ready': ('info', self.tr('SYSTEM READY...')),
            'confirm_exit': ('warning', self.tr('DO YOU WANT TO EXIT?')),
            'confirm_credit': ('question', self.tr('PLEASE CONFIRM YOUR PAYMENT TERM AS CREDIT?')),
            'sale_number_not_found': ('warning', self.tr('SALE ORDER / INVOICE NUMBER NOT FOUND!')),
            'sale_closed': ('error', self.tr('THIS SALE IS CLOSED, YOU CAN NOT TO MODIFY!')),
            'discount_not_valid': ('warning', self.tr('DISCOUNT VALUE IS NOT VALID!')),
            'add_payment_sale_draft': ('info', self.tr('YOU CAN NOT ADD PAYMENTS TO SALE ON DRAFT STATE!')),
            'enter_quantity': ('question', self.tr('ENTER QUANTITY...')),
            'enter_discount': ('question', self.tr('ENTER DISCOUNT...')),
            'enter_payment': ('question', self.tr('ENTER PAYMENT AMOUNT BY: %s')),
            'enter_new_price': ('question', self.tr('ENTER NEW PRICE...')),
            'order_successfully': ('info', self.tr('ORDER SUCCESUFULLY SENT.')),
            'order_failed': ('warning', self.tr('FAILED SEND ORDER!')),
            'missing_agent': ('warning', self.tr('MISSING AGENT!')),
            'missing_salesman': ('warning', self.tr('THERE IS NOT SALESMAN FOR THE SALE!')),
            'sale_without_products': ('warning', self.tr('YOU CAN NOT CONFIRM A SALE WITHOUT PRODUCTS!')),
            'user_without_permission': ('error', self.tr('USER WITHOUT PERMISSION FOR SALE POS!')),
            'quantity_not_valid': ('error', self.tr('THE QUANTITY IS NOT VALID...!')),
            'user_not_permissions_device': ('error', self.tr('THE USER HAVE NOT PERMISSIONS FOR ACCESS TO DEVICE!')),
            'missing_party_configuration': ('warning', self.tr('MISSING THE DEFAULT PARTY ON SHOP CONFIGURATION!')),
            'missing_journal_device': ('error', self.tr('MISSING SET THE JOURNAL ON DEVICE!')),
            'statement_closed': ('error', self.tr('THERE IS NOT A STATEMENT OPEN FOR THIS DEVICE!')),
            'product_not_found': ('warning', self.tr('PRODUCT NOT FOUND!')),
            'must_load_or_create_sale': ('warning', self.tr('FIRST YOU MUST CREATE/LOAD A SALE!')),
            'new_sale': ('warning', self.tr('DO YOU WANT CREATE NEW SALE?')),
            'cancel_sale': ('question', self.tr('ARE YOU WANT TO CANCEL SALE?')),
            'not_permission_delete_sale': ('info', self.tr('YOU HAVE NOT PERMISSIONS FOR DELETE THIS SALE!')),
            'not_permission_for_cancel': ('info', self.tr('YOU HAVE NOT PERMISSIONS FOR CANCEL THIS SALE!')),
            'customer_not_credit': ('info', self.tr('THE CUSTOMER HAS NOT CREDIT!')),
            'agent_not_found': ('warning', self.tr('AGENT NOT FOUND!')),
            'invalid_commission': ('warning', self.tr('COMMISSION NOT VALID!')),
            'credit_limit_exceed': ('info', self.tr('CREDIT LIMIT FOR CUSTOMER EXCEED!')),
            'credit_limit_capacity': ('info', self.tr('THE CUSTOMER CREDIT CAPACITY IS ABOVE 80%')),
            'not_can_force_assign': ('warning', self.tr('YOU CAN NOT FORCE ASSIGN!')),
            'send_electronic_failed': ('info', self.tr('FALLO EL ENVIO DE FACTURA!')),
            'invoice_done_failed': ('info', self.tr('FALLO FINALIZACIÓN DE FACTURA!')),
            'without_stock_quantity': ('info', self.tr('PRODUCT WITHOUT STOCK: %s')),
            'not_sale': ('info', self.tr('NOT SALE!...')),
            'statement_created': ('info', self.tr('STATEMENTS CREATED!')),
            'statement_finish': ('info', self.tr('STATEMENTS CLOSED!')),
            'order_dispatched': ('info', self.tr('ORDER DISPATCHED!')),
            'error_order_dispatched': ('error', self.tr('ERROR TO DISPATCHED ORDER!')),
        }
        self.stack_msg = messages

    def create_dialogs(self):
        self.dialog_control_panel = ControlPanel(self).get(self.menu_control_panel)
        self.dialog_money_count = DialogTableMoneyCount(self).get()
        self.dialog_search_sales = SearchSale(self).get()
        self.dialog_search_parties = SearchParty(self).get()
        self.dialog_search_products = SearchProduct(self).get()
        self.dialog_position = Position(self).get()
        self.dialog_tip_amount = TipAmount(self).get()
        self.dialog_delivery_amount = DeliveryAmount(self).get()
        self.dialog_comment = Comment(self).get()
        self.dialog_payment = DialogPayment(self).get()
        self.dialog_salesman = DialogSalesman(self).get()
        self.dialog_voucher = DialogVoucher(self).get()
        self.dialog_print_invoice = DialogPrintInvoice(self).get()
        self.dialog_global_discount = DialogGlobalDiscount(self).get()
        self.dialog_global_discount_table = DialogGlobalDiscountTable(self).get()
        self.dialog_payment_term = DialogPaymentTerm(self).get()
        self.dialog_search_sales.activate_counter()
        self.dialog_product_stock = DialogStock(self.dialog_search_products).get()
        self.dialog_order = DialogOrder(self).get()
        self.dialog_force_assign = DialogForceAssign(self).get()
        self.field_password_force_assign_ask.setEchoMode(QLineEdit.Password)
        self.dialog_tax = DialogTaxes(self).get()
        self.dialog_cancel_invoice = DialogCancelInvoice(self).get()
        self.dialog_product_edit = EditLine(self).get()
        self.dialog_table_delivery_party = DialogTableDeliveryParty(self).get()
        self.dialog_delivery_party_selected = DeliveryPartySelected(self).get()
        self.dialog_delivery_party = DialogDeliveryParty(self).get()
        if self._web_channel:
            self.dialog_channel = DialogChannel(self).get()
        if self._commission_activated:
            self.dialog_agent = DialogAgent(self).get()
        if self.enviroment == 'restaurant' and self._sale_pos_restaurant:
            self.dialog_addition_product = AdditionProduct(self)
            self.dialog_table_sale_consumer = DialogTableSaleConsumer(self).get()
            self.dialog_sale_consumer_selected = SaleConsumerSelected(self).get()
            self.dialog_search_consumer = DialogConsumer(self).get()
            self.manage_tables = DialogManageTables(self)
            self.dialog_manage_tables = self.manage_tables.get()

    def action_help(self):
        Help(self).show()

    def resize_window_tablet_dev(self):
        self.resize(690, self.get_geometry()[1])

    def load_modules(self):
        self._sale_pos_restaurant = None
        self.Module = FastModel('ir.module', self.ctx)
        self.Config = FastModel('sale.configuration', self.ctx)
        self._config, = self.Config.find([('id', '=', 1)])
        self.discount_method = self._config.get('discount_pos_method')
        self.sale_automatic = False
        if self.enviroment == 'retail' and self._config.get('new_sale_automatic'):
            self.sale_automatic = True
        self._commission_activated = self.Module.find([
            ('name', '=', 'commission'),
            ('state', '=', 'activated'),
        ])
        self._web_channel = self.Module.find([
            ('name', '=', 'sale_web_channel'),
            ('state', '=', 'activated'),
        ])
        self._credit_limit_activated = self.Module.find([
            ('name', '=', 'account_credit_limit'),
            ('state', '=', 'activated'),
        ])

        _product = {
            'name': 'product.product',
            'fields': [
                'template.name', 'code', 'barcode', 'write_date',
                'description', 'template.sale_price_w_tax',
                'template.account_category'
            ]
        }
        self.cache_local = self._config.get('cache_products_local')

        if self._config['show_location_pos']:
            _product['fields'].append('location_')

        if self._config['show_stock_pos'] in ('value', 'icon'):
            if self._config['show_stock_pos'] == 'value':
                _product['fields'].append('quantity')
        if self._config['show_brand']:
            _product['fields'].append('brand.name')

        if self._config['encoded_sale_price']:
            _product['fields'].extend(['image', 'image_icon', 'encoded_sale_price'])

        if self.enviroment == 'restaurant':
            self._sale_pos_restaurant = self.Module.find([
                ('name', '=', 'sale_pos_frontend_rest'),
                ('state', '=', 'activated'),
            ])
            if self._sale_pos_restaurant:
                self.PartyConsumer = FastModel('party.consumer', self.ctx)
                if self._config['delivery_product']:
                    self._delivery_product = 0

        self.User = FastModel('res.user', self.ctx)
        self._user, = self.User.find([('login', '=', self.user)])
        self.Company = FastModel('company.company', self.ctx)
        self._company, = self.Company.find([('id', '=', 1)])
        self.logo = self._company['logo']

        if not self._user['sale_device']:
            return 'user_not_permissions_device'

        self.ctx['user'] = self._user['id']

        self.Sale = FastModel('sale.sale', self.ctx)
        self.SaleLine = FastModel('sale.line', self.ctx)
        self.Product = FastModel('product.product', self.ctx)
        self.Journal = FastModel('account.statement.journal', self.ctx)
        self.Employee = FastModel('company.employee', self.ctx)
        self.Shop = FastModel('sale.delivery_party', self.ctx)
        self.SaleDiscont = FastModel('sale.discount', self.ctx)
        self.Device = FastModel('sale.device', self.ctx)
        self.Category = FastModel('product.category', self.ctx)
        self.PaymentTerm = FastModel('account.invoice.payment_term', self.ctx)
        self.Party = FastModel('party.party', self.ctx)
        self.DeliveryParty = FastModel('sale.delivery_party', self.ctx)
        self.Taxes = FastModel('account.tax', self.ctx)
        self.ActionReport = FastModel('ir.action.report', self.ctx)
        if self._commission_activated:
            self.Agent = FastModel('commission.agent', self.ctx)
            self.Comission = FastModel('commission', self.ctx)
        if self._sale_pos_restaurant:
            self.RestTables = FastModel('sale.shop.table', self.ctx)
            self.Consumer = FastModel('party.consumer', self.ctx)

        self.device, = self.Device.find([
            ('id', '=', self._user['sale_device']['id']),
        ])

        self.shop = self.device['shop']
        self.shop_taxes = self.shop['taxes']
        self.company = self.shop['company']
        self._journals = self.device['journals']
        self.salesman_ids = [s['id'] for s in self.shop.get('salesmans', [])]

        dom_salesman = [
            ('company', '=', self.company['id']),
        ]
        if self.salesman_ids:
            dom_salesman.append(('id', 'in', self.salesman_ids))
        self.employees = self.Employee.find(dom_salesman)

        self.discounts = self.shop.get('discounts', [])
        self.delivery_man_table = self.shop.get('delivery_man', [])
        self.delivery_man = [d for d in self.delivery_man_table if d['active']]
        self._payment_terms = self.PaymentTerm.find([('active', '=', True)])
        self.type_pos_user = self._context.get('type_pos_user')

        if not self.type_pos_user:
            return 'user_without_permission'
        self.user_can_delete = self.type_pos_user in ('frontend_admin', 'cashier')

        self.product_categories = self.device['shop']['product_categories']
        self.salesman_required = self.device['shop']['salesman_pos_required']

        self.default_party = self.shop['party']
        if not self.default_party:
            return 'missing_party_configuration'

        self.default_journal = self.device['journal']
        if not self.default_journal:
            return 'missing_journal_device'

        self.default_payment_term = self.shop['payment_term']
        self._password_admin = self._config.get('password_admin_pos')
        self._password_force_assign = self._config.get('password_force_assign')

        self._action_report, = self.ActionReport.find([
            ('report_name', '=', 'account.invoice'),
        ])
        if self._config['show_stock_pos'] in ('value', 'icon'):
            self.stock_context = {
                'stock_date_end': date.today(),
                'locations': [self.shop['warehouse']['id']],
            }
        if self._web_channel:
            self.Channel = FastModel('sale.web_channel', self.ctx)
        return True

    def create_statusbar(self):
        values = OrderedDict([
            ('stb_shop', {'name': self.tr('SHOP'), 'value': self.shop['name']}),
            ('stb_device', {'name': self.tr('DEVICE'), 'value': self.device['name']}),
            ('stb_database', {'name': self.tr('DATABASE'), 'value': self.database}),
            ('stb_user', {'name': self.tr('USER'), 'value': self.user}),
            ('stb_printer', {'name': self.tr('PRINTER'), 'value': self.printer_sale_name})
        ])
        self.set_statusbar(values)


class ClearUi(QThread):
    sigActionClear = pyqtSignal()
    state = None

    def __init__(self, wait_time):
        QThread.__init__(self)
        self.wait_time = wait_time

    def run(self):
        time.sleep(self.wait_time)
        self.sigActionClear.emit()
