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

import re

from ppms import ppms
from ppms.migration import ChangeDTPPacket, SQLPacket, PacketCategory,\
    MinVersionDependency, MaxVersionDependency, VersionType


class DataItem():
    """Helper class to handle DIs and their formula code."""

    LOWERCASE_DEPS_RE_STR = r'''
        (\.deps\s*=\s*\(  # beginning of tuple
        [^)]*             # anything but closing parenthese
        di\d{6}           # the lowercase dependencies we're looking for
        [^)]*             # anything but closing parenthese
        \))               # end of tuple
    '''
    LOWERCASE_DEPS_RE = re.compile(LOWERCASE_DEPS_RE_STR, re.DOTALL | re.VERBOSE)

    LOWERCASE_DI_REF_RE_STR = r'di(\d{6})'
    LOWERCASE_DI_REF_RE = re.compile(LOWERCASE_DI_REF_RE_STR, re.DOTALL | re.VERBOSE)


    @classmethod
    def get_raw_list(cls, sql_packet):
        return sql_packet.select_or_log("""
            select
                di000238 id,
                di001990 wb_type,
                di027352 valuerange
            from dt412 di
            where di.enabled = 1
            and di.di001990 = 'PY'
            and di.di027352 like '%.deps%'
            and exists(
                select 1 from dt415 dt
                where di.di000239 = dt.di000265
                and dt.enabled = 1
                and exists (
                    select 1 from dt420 ds
                    where dt.di000266 = ds.di000289
                    and ds.enabled = 1
                )
            ) order by id
            """)

    @classmethod
    def get_list(cls, sql_packet):
        all_dis_with_py_deps = (DataItem(id, type, code) for id, type, code in cls.get_raw_list(sql_packet))
        return [di for di in all_dis_with_py_deps if di.has_match]


    id = None
    formula_type = None
    formula_old = None
    formula_new = None
    has_match = False

    def __init__(self, id, type, code):
        self.id = id
        self.formula_type = type
        self.formula_old = code

        self.formula_new = self.LOWERCASE_DEPS_RE.sub(self.replace_ref_in_deps, code)
        self.has_match = self.formula_old != self.formula_new

    def replace_ref_in_deps(self, match):
        return self.LOWERCASE_DI_REF_RE.sub(r'DI\1', match.group(0))

    def write_formula(self, dtp_packet):
        di_record = dtp_packet.get_record(412, [self.id], ['valuerange'])
        dtp_packet.change_value(di_record, 'valuerange', self.formula_old, self.formula_new)



class FixLowercasePythonFormulaDepedencies(ChangeDTPPacket, SQLPacket):
    """Replaces lowercase DI dependencies in Python formulae with their proper uppercase equivalent."""

    version = 1
    run_on_startup = True
    done_after_success = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 13831

    def get_dependencies(self):
        return (MinVersionDependency(version='39.4', version_type=VersionType.CUSTOMIZING),
                MaxVersionDependency(version='39.5.5', version_type=VersionType.CUSTOMIZING))

    def fix(self, runner):
        prev_state = ppms.db_get_auto_commit()
        ppms.db_set_auto_commit(False)

        dis_to_update = DataItem.get_list(self)

        try:
            for di in dis_to_update:
                #self.log('DI {} will have >>>\n{}\n<<< replaced with >>>\n{}\n<<<'
                #         .format(di.id, di.formula_old, di.formula_new))
                di.write_formula(self)

            ppms.db_commit()
            return self.success()
        except ppms.DatabaseError:
            ppms.db_rollback()
            raise
        finally:
            ppms.db_set_auto_commit(prev_state)
