# encoding: UTF-8
from sqlalchemy import func

from ..model.caseModel import CaseReview, CaseSnapshot, Module, TestCase
from logger import logger


class CaseDao(object):
    """用例域通用 DAO，复用模块、用例、快照、评审的基础操作。"""

    @staticmethod
    def create(session, model_cls, add_info):
        """创建记录并提交事务。"""
        obj = model_cls(**add_info)
        session.add(obj)
        err = session.done(close=False)
        if err:
            logger.warning(f'{model_cls.__name__}新增失败！{err}')
            return 0, f'新增失败！{err}'
        return obj.id, ''

    @staticmethod
    def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
        filters = [model_cls.id == int(obj_id)]
        if soft_delete and hasattr(model_cls, 'is_delete'):
            filters.append(model_cls.is_delete == 0)
        update_res = session.query(model_cls).filter(*filters).update(update_info)
        err = session.done(close=False)
        if err:
            logger.error(f'{model_cls.__name__}更新失败！id: {obj_id}, err: {err}')
            return 0, f'更新失败！{err}'
        if not update_res:
            return 0, '未查询到对应记录！'
        return int(obj_id), ''

    @staticmethod
    def get_by_id(session, model_cls, obj_id, soft_delete=True):
        filters = [model_cls.id == int(obj_id)]
        if soft_delete and hasattr(model_cls, 'is_delete'):
            filters.append(model_cls.is_delete == 0)
        return session.query(model_cls).filter(*filters).first()

    @staticmethod
    def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
        query = session.query(model_cls).filter(*filter_list)
        if hasattr(model_cls, 'is_delete'):
            query = query.filter(model_cls.is_delete == 0)
        total = query.count()
        if order_column is not None:
            query = query.order_by(order_column.desc())
        rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
        return rets, total

    @staticmethod
    def delete_by_id(session, model_cls, obj_id):
        return CaseDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})

    @staticmethod
    def next_case_key(session, project_id, module_id=None, product_id=None):
        from ..model.productModel import Product
        from ..model.projectModel import Project
        from ..model.caseModel import Module
        
        product_abbr = ''
        if product_id:
            product = session.query(Product).filter(Product.id == int(product_id), Product.is_delete == 0).first()
            if product and product.name:
                product_abbr = CaseDao._generate_abbreviation(product.name)
        
        project_abbr = ''
        project = session.query(Project).filter(Project.id == int(project_id), Project.is_delete == 0).first()
        if project and project.name:
            project_abbr = CaseDao._generate_abbreviation(project.name)
        
        module_abbr = ''
        if module_id:
            module = session.query(Module).filter(Module.id == int(module_id), Module.is_delete == 0).first()
            if module and module.name:
                module_abbr = CaseDao._generate_abbreviation(module.name)
        
        parts = ['TC']
        if product_abbr:
            parts.append(product_abbr)
        if project_abbr:
            parts.append(project_abbr)
        if module_abbr:
            parts.append(module_abbr)
        
        prefix = '-'.join(parts)
        
        count_num = session.query(func.count(TestCase.id)).filter(
            TestCase.project_id == int(project_id),
            TestCase.is_delete == 0,
            TestCase.case_key.like(f'{prefix}-%')
        ).scalar() or 0
        
        return '{}-{:03d}'.format(prefix, count_num + 1)
    
    @staticmethod
    def _generate_abbreviation(name):
        import re
        chinese_pattern = re.compile(r'[\u4e00-\u9fff]+')
        english_pattern = re.compile(r'[a-zA-Z]+')
        
        chinese_chars = chinese_pattern.findall(name)
        if chinese_chars:
            full_chinese = ''.join(chinese_chars)
            abbr = ''.join([CaseDao._get_pinyin_first_char(c) for c in full_chinese[:4]])
            abbr = abbr.lower()
            if len(abbr) < 2:
                abbr = abbr.ljust(2, 'n')
            return abbr
        
        english_words = english_pattern.findall(name)
        if english_words:
            abbr = english_words[0].lower()[:4]
            if len(abbr) < 2:
                abbr = abbr.ljust(2, 'x')
            return abbr
        
        abbr = name.lower()[:4]
        if len(abbr) < 2:
            abbr = abbr.ljust(2, 'x')
        return abbr
    
    @staticmethod
    def _get_pinyin_first_char(char):
        pinyin_map = {
            '智': 'Z', '慧': 'H', '运': 'Y', '营': 'Y',
            '报': 'B', '关': 'G', '工': 'G', '作': 'Z', '台': 'T',
            '测': 'C', '试': 'S', '用': 'Y', '例': 'L',
            '产': 'C', '品': 'P', '项': 'X', '目': 'M',
            '模': 'M', '块': 'K', '管': 'G', '理': 'L',
            '系': 'X', '统': 'T', '功': 'G', '能': 'N',
            '页': 'Y', '面': 'M', '查': 'C', '询': 'X',
            '添': 'T', '加': 'J', '编': 'B', '辑': 'J',
            '删': 'S', '除': 'C', '导': 'D', '入': 'R',
            '导': 'D', '出': 'C', '批': 'P', '量': 'L',
            '设': 'S', '置': 'Z', '配': 'P', '置': 'Z',
            '权': 'Q', '限': 'X', '角': 'J', '色': 'S',
            '用': 'Y', '户': 'H', '组': 'Z', '织': 'Z',
            '计': 'J', '划': 'H', '执': 'Z', '行': 'X',
            '报': 'B', '告': 'G', '统': 'T', '计': 'J',
            '首': 'S', '页': 'Y', '仪': 'Y', '表': 'B',
            '烟': 'Y', '冒': 'M', '回': 'H', '归': 'G',
            '集': 'J', '成': 'C', '接': 'J', '口': 'K',
            '安': 'A', '全': 'Q', '日': 'R', '志': 'Z',
            '监': 'J', '控': 'K', '优': 'Y', '化': 'H',
            '性': 'X', '能': 'N', '首': 'S', '尾': 'W',
            '开': 'K', '发': 'F', '测': 'C', '运': 'Y',
            '维': 'W', '设': 'S', '计': 'J', '研': 'Y',
            '发': 'F', '部': 'B', '组': 'Z', '个': 'G',
            '人': 'R', '公': 'G', '司': 'S', '有': 'Y',
            '限': 'X', '责': 'Z', '任': 'R', '股': 'G',
            '份': 'F', '集': 'J', '团': 'T', '科': 'K',
            '技': 'J', '网': 'W', '络': 'L', '信': 'X',
            '息': 'X', '软': 'R', '件': 'J', '系': 'X',
            '统': 'T', '解': 'J', '决': 'J', '方': 'F',
            '案': 'A', '服': 'F', '务': 'W', '支': 'Z',
            '持': 'C', '培': 'P', '训': 'X', '咨': 'Z',
            '询': 'X', '销': 'X', '售': 'S', '市': 'S',
            '场': 'C', '运': 'Y', '营': 'Y', '管': 'G',
            '理': 'L', '财': 'C', '务': 'W', '人': 'R',
            '力': 'L', '资': 'Z', '源': 'Y', '行': 'X',
            '政': 'Z', '法': 'F', '律': 'L', '合': 'H',
            '规': 'G', '质': 'Z', '量': 'L', '安': 'A',
            '全': 'Q', '环': 'H', '境': 'J', '职': 'Z',
            '能': 'N', '模': 'M', '块': 'K', '页': 'Y',
            '面': 'M', '窗': 'C', '口': 'K', '表': 'B',
            '单': 'D', '按': 'A', '钮': 'N', '链': 'L',
            '接': 'J', '图': 'T', '标': 'B', '菜': 'C',
            '单': 'D', '导': 'D', '航': 'H', '搜': 'S',
            '索': 'S', '过': 'G', '滤': 'L', '排': 'P',
            '序': 'X', '分': 'F', '页': 'Y', '导': 'D',
            '入': 'R', '导': 'D', '出': 'C', '打': 'D',
            '印': 'Y', '导': 'D', '出': 'C', '删': 'S',
            '除': 'C', '复': 'F', '制': 'Z', '粘': 'N',
            '贴': 'T', '剪': 'J', '切': 'Q', '保': 'B',
            '存': 'C', '取': 'Q', '消': 'X', '确': 'Q',
            '认': 'R', '提': 'T', '交': 'J', '审': 'S',
            '核': 'H', '批': 'P', '准': 'Z', '拒': 'J',
            '绝': 'J', '返': 'F', '回': 'H', '修': 'X',
            '改': 'G', '查': 'C', '看': 'K', '详': 'X',
            '情': 'Q', '列': 'L', '表': 'B', '统': 'T',
            '计': 'J', '图': 'T', '表': 'B', '报': 'B',
            '告': 'G', '日': 'R', '志': 'Z', '备': 'B',
            '注': 'Z', '描': 'M', '述': 'S', '名': 'M',
            '称': 'C', '编': 'B', '号': 'H', '类': 'L',
            '型': 'X', '状': 'Z', '态': 'T', '优': 'Y',
            '先': 'X', '级': 'J', '标': 'B', '签': 'Q',
            '关': 'G', '键': 'J', '词': 'C', '描': 'M',
            '述': 'S', '附': 'F', '件': 'J', '链': 'L',
            '接': 'J', '时': 'S', '间': 'J', '日': 'R',
            '期': 'Q', '数': 'S', '量': 'L', '金': 'J',
            '额': 'E', '价': 'J', '格': 'G', '数': 'S',
            '据': 'J', '库': 'K', '服': 'F', '务': 'W',
            '器': 'Q', '线': 'X', '程': 'C', '进': 'J',
            '度': 'D', '速': 'S', '度': 'D', '效': 'X',
            '率': 'L', '性': 'X', '能': 'N', '稳': 'W',
            '定': 'D', '可': 'K', '靠': 'K', '安': 'A',
            '全': 'Q', '兼': 'J', '容': 'R', '扩': 'K',
            '展': 'Z', '升': 'S', '级': 'J', '更': 'G',
            '新': 'X', '修': 'X', '补': 'B', '修': 'X',
            '复': 'F', '优': 'Y', '化': 'H', '重': 'Z',
            '构': 'G', '改': 'G', '造': 'Z', '移': 'Y',
            '植': 'Z', '集': 'J', '成': 'C', '接': 'J',
            '口': 'K', '调': 'T', '试': 'S', '测': 'C',
            '试': 'S', '验': 'Y', '证': 'Z', '确': 'Q',
            '认': 'R', '回': 'H', '归': 'G', '演': 'Y',
            '示': 'S', '培': 'P', '训': 'X', '指': 'Z',
            '导': 'D', '支': 'Z', '持': 'C', '帮': 'B',
            '助': 'Z', '反': 'F', '馈': 'K', '投': 'T',
            '诉': 'S', '建': 'J', '议': 'Y', '评': 'P',
            '独': 'D', '立': 'L', '站': 'Z', '采': 'C',
            '购': 'G', '供': 'G', '应': 'Y', '商': 'S',
            '价': 'J', '满': 'M', '意': 'Y', '度': 'D'
        }
        return pinyin_map.get(char, 'N')

    @staticmethod
    def next_snapshot_version(session, case_id):
        """生成用例快照版本号。"""
        max_version = session.query(func.max(CaseSnapshot.version)).filter(CaseSnapshot.case_id == int(case_id)).scalar() or 0
        return int(max_version) + 1

    @staticmethod
    def module_model():
        return Module

    @staticmethod
    def case_model():
        return TestCase

    @staticmethod
    def snapshot_model():
        return CaseSnapshot

    @staticmethod
    def review_model():
        return CaseReview

    @staticmethod
    def get_module_name_map(session, module_ids):
        if not module_ids:
            return {}
        module_items = session.query(Module).filter(Module.id.in_(module_ids), Module.is_delete == 0).all()
        return {module.id: module.name for module in module_items}
