import json
from typing import Union

import persistence
import pyscripts
import sysactions

mb_context = pyscripts.mbcontext
_modifiers = None
_sub_modifiers = {}

MODIFIERS_QUERY = """
SELECT DISTINCT *
FROM (
    SELECT 
        P1.ProductCode AS productCode,
        TRIM(REPLACE(P1.ProductName, '"', '')) AS productName,
        P2.ProductCode AS modifierCode,
        TRIM(REPLACE(P2.ProductName, '"', '')) AS modifierName,
        COALESCE((
                SELECT 1
                FROM ProductClassification
                WHERE ClassCode = P2.ProductCode LIMIT 1
                ), 0) AS isOption,
        COALESCE((
                SELECT 1
                FROM ProductKernelParams
                WHERE ProductCode = P2.ProductCode
                    AND ProductType = 2 LIMIT 1
                ), 0) AS isCombo,
        COALESCE((
                SELECT 1
                FROM ProductCustomParams
                WHERE ProductCode = P2.ProductCode
                    AND CustomParams.CustomParamId = 'CFH' COLLATE NOCASE
                    AND CustomParams.CustomParamValue = 'true' COLLATE NOCASE LIMIT 1
                ), 0) AS isCFH,
        (
            SELECT ('[' || COALESCE(GROUP_CONCAT('[' ||
                PC.ProductCode || ',"' ||
                TRIM(REPLACE(PPC.ProductName, '"', '')) || '", ' ||
                TRIM(
                    CASE WHEN PC.CustomAttr IS NULL OR PC.CustomAttr = ''
                    THEN '{}'
                    ELSE PC.CustomAttr
                    END
                ) ||']') , '') ||
                ']')
            FROM ProductClassification PC
            INNER JOIN Product PPC ON PPC.ProductCode = PC.ProductCode
            WHERE PC.ClassCode = P2.ProductCode
            ) AS options,
        PP.MinQty AS minQty,
        PP.MaxQty AS maxQty,
        PP.DefaultQty AS defaultQty,
        PP.IncludedQty AS includedQty,
        PP.CustomAttr AS customAttr
    FROM ProductPart PP
    INNER JOIN Product P1 ON P1.ProductCode = PP.ProductCode
    INNER JOIN Product P2 ON P2.ProductCode = PP.PartCode
    LEFT JOIN ProductCustomParams CustomParams ON CustomParams.ProductCode = PP.PartCode
    ) T
ORDER BY productCode, modifierCode
"""


@sysactions.action
def get_modifiers_data(_):
    return json.dumps(get_cached_modifiers())


def get_cached_modifiers():
    global _modifiers
    global _sub_modifiers

    if _modifiers is None:
        _sub_modifiers = {}
        conn = persistence.Driver().open(mb_context)
        modifiers = {}

        cursor = conn.select(MODIFIERS_QUERY)
        if cursor.rows() > 0:
            for row in cursor:
                get_modifier_product_data(_sub_modifiers, cursor, modifiers, row)

        conn.close()
        _modifiers = modifiers

    return {'modifiers': _modifiers, 'descriptions': _sub_modifiers}


# noinspection PyBroadException
def get_modifier_product_data(_sub_modifiers, cursor, modifiers, row):
    prod_code, prod_name, mod_code, mod_name, is_option, is_combo, is_cfh, options = map(row.get_entry, range(8))
    part_data = dict(zip(map(cursor.get_name, range(8, 13)), map(row.get_entry, range(8, 13))))

    if prod_code not in modifiers:
        modifiers[prod_code] = {'name': prod_name, 'parts': {}}

    if mod_code not in _sub_modifiers:
        _sub_modifiers[str(mod_code)] = mod_name

    if int(is_option) > 0 and options is not None:
        part_data['options'] = []
        options = options.replace("\\", "\\\\")
        for p_code, p_name, p_custom_attributes in json.loads(options):
            hide_on_pos_type = p_custom_attributes["hideOnPosType"] if "hideOnPosType" in p_custom_attributes else []
            part_sequencer = p_custom_attributes["partSequencer"] if "partSequencer" in p_custom_attributes else []
            part_data['options'].append(
                {"code": int(p_code), "hideOnPosType": hide_on_pos_type, "partSequencer": part_sequencer}
            )
            _sub_modifiers[str(p_code)] = p_name

    if 'customAttr' in part_data:
        try:
            if part_data['customAttr'] is not None:
                part_data['customAttr'] = json.loads(part_data['customAttr'])
        except Exception as _:
            pass
    else:
        part_data['customAttr'] = None

    if mod_code not in modifiers[prod_code]['parts']:
        modifiers[prod_code]['parts'][mod_code] = {
            'isOption': int(is_option) > 0,
            'isCombo': int(is_combo) > 0,
            'isCFH': int(is_cfh) > 0,
            'data': part_data
        }
