#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
@File    :   filter_page.py
@Time    :   2024/11/21 14:55:10
@Author  :   dulip3ng
@Version :   1.0
@Desc    :   None
'''
import re
import time

from pages.locator.filter_page_locator import FilterPageLocator
from playwright.sync_api import Page, expect
from common.field_type import FieldType
from common.condition_row import ConditionRow
from pages.base_page import BasePage

class FilterPage(BasePage):
    """
    过滤弹出框页面模型，适用于普通过滤弹出框，如在列表中点击过滤后弹出的过滤框
    """

    def check_all_org(self):
        """
        勾选所有组织复选框，如果已经是勾选状态则不操作

        **用法：**

        FilterPage.check_all_org()
        :return:
        """
        # 多数情况下勾选所有组织是过滤界面第一个操作，偶发点击失效情况，加入2s等待时间确保稳定性
        time.sleep(2)
        locator_click = self.page.locator(FilterPageLocator.ALL_ORG_LOC)
        locator_get_state = self.page.locator(FilterPageLocator.ALL_ORG_GET_CHECK_STATE_LOC)
        expect(locator_click).to_be_enabled()
        print(locator_get_state.is_checked())
        if not locator_get_state.is_checked():
            locator_click.click()

    def uncheck_all_org(self):
        """
        取消勾选所有组织复选框，如果已经未勾选状态则不操作

        **用法：**

        FilterPage.uncheck_all_org()
        :return:
        """
        # 多数情况下勾选所有组织是过滤界面第一个操作，偶发点击失效情况，加入2s等待时间确保稳定性
        time.sleep(2)
        locator_click = self.page.locator(FilterPageLocator.ALL_ORG_LOC)
        locator_get_state = self.page.locator(FilterPageLocator.ALL_ORG_GET_CHECK_STATE_LOC)
        expect(locator_click).to_be_enabled()
        print(locator_get_state.is_checked())
        if locator_get_state.is_checked():
            print("22")
            locator_click.click()

    def check_org(self, *orgs:str):
        """
        根据给定组织编码或名称，勾选组织

        **用法：**

        FilterPage.check_org("100.1")

        FilterPage.check_org("100.1", "鲁泰纺织股份")
        :param orgs: 组织编码或名称，可传多个，模糊匹配
        :return:
        """
        self.page.locator(FilterPageLocator.ORG_ARROW_LOC).click()
        for org in orgs:
            self.page.locator(FilterPageLocator.ORG_MULTI_ITEM_ARGS_LOC % org).click()
        self.page.locator(FilterPageLocator.ORG_SELECT_OK_BTN_LOC).click()

    def check_entity(self, *entitys_name:str):
        """
        根据给定实体，勾选实体

        **用法：**

        FilterPage.check_entity("明细信息")

        FilterPage.check_entity("明细信息", "财务信息")

        **注意：**

        未进行勾选状态判断，未勾选状态下调用一次为勾选，再次调用为取消勾选
        :param entitys_name: 实体名称
        :return:
        """
        for entity in entitys_name:
            self.page.locator(FilterPageLocator.ENTITY_CHECKBOX_ARGS_LOC % entity).click()

    def click_tool_bar_button(self, button_name:str):
        """
        点击过滤框页面菜单行按钮

        **用法：**

        FilterPage.click_tool_bar_button("删除全部")
        :param button_name: 按钮名称
        :return:
        """
        self.page.locator(FilterPageLocator.TOOL_BAR_BTN_ARGS_LOC % button_name).click()

    def set_condition(self, row:int, condition_name:str):
        """
        按行设置过滤条件项

        **用法：**

        FilterPage.set_condition(1, "基本信息-衬衣订单号")

        **注意：**

        部分单据中存在相同字段名在不同页签的情况，此时模糊匹配无法找到正确选项值，推荐使用条件项全称精确匹配
        :param row: 行号，从1开始
        :param condition_name: 条件项全称
        :return:
        """
        self.click_tool_bar_button("新增行")
        locator = self.page.locator(FilterPageLocator.FILTER_CONDITION_ARGS_LOC % ((row - 1) * 35))
        locator.fill(condition_name)
        # 条件项赋值后默认不弹出选项框，输入空格再删除，以便弹出选项框进行选择
        locator.press_sequentially(" ")
        locator.press("Backspace")
        self.page.locator(FilterPageLocator.CONDITION_ITEM_ARGS_LOC % condition_name).click()

    def set_operator(self, row:int, operator:str):
        """
        设置过滤条件操作符号

        **用法：**

        FilterPage.set_operator(1, "包含")
        :param row: 行号
        :param operator: 操作符名称
        :return:
        """
        self.page.locator(FilterPageLocator.COMPARE_TYPE_ARGS_LOC % ((row - 1) * 35)).click()
        self.page.locator(FilterPageLocator.COMPARE_ITEM_ARGS_LOC % operator).click()

    def _set_text(self, row:int, value:str):
        """
        条件值字段，文本字段类型赋值

        **用法：**

        FilterPage.set_text(1, "内销")

        使用FilterPage.set_condition_value()方法代替，此方法无需区分字段类型
        :param row: 行号，从1开始
        :param value: 条件值
        :return:
        """
        self.page.locator(FilterPageLocator.CONDITION_TEXT_FIELD_ARGS_LOC % ((row - 1) * 35)).fill(value)

    def _set_date(self, row:int, value:str):
        """
        条件值字段，日期字段类型赋值

        **用法：**

        FilterPage.set_date(1, "2024-11-25")

        使用FilterPage.set_condition_value()方法代替，此方法无需区分字段类型
        :param row: 行号，从1开始
        :param value: 条件值，格式"2024-11-25"
        :return:
        """
        self.page.locator(FilterPageLocator.CONDITION_DATE_FIELD_ARGS_LOC % ((row - 1) * 35)).fill(value)
        self.click_blank()

    def _set_select(self, row:int, value:str):
        """
        条件值字段，下拉列表字段类型赋值

        **用法：**

        FilterPage.set_select(1, "创建")

        使用FilterPage.set_condition_value()方法代替，此方法无需区分字段类型
        :param row: 行号，从1开始
        :param value: 条件值
        :return:
        """
        self.page.locator(FilterPageLocator.CONDITION_SELECT_FIELD_ARGS_LOC % ((row - 1) * 35)).click()
        self.page.locator(FilterPageLocator.CONDITION_SELECT_ITEM_ARGS_LOC % value).click()

    def _set_base(self, row:int, value:str):
        """
        条件值字段，基础资料字段类型赋值

        **用法：**

        FilterPage.set_base(1, "P010001")

        使用FilterPage.set_condition_value()方法代替，此方法无需区分字段类型
        :param row: 行号，从1开始
        :param value: 条件值
        :return:
        """
        # CONDITION_BASE_FIELD_ARGS_LOC input元素可操作性检查不通过，CONDITION_BASE_FIELD_SPAN_ARGS_LOC span劫持，这里直接对span进行点击
        self.page.locator(FilterPageLocator.CONDITION_BASE_FIELD_SPAN_ARGS_LOC % ((row - 1) * 35)).click()
        self.page.locator(FilterPageLocator.CONDITION_BASE_FIELD_ARGS_LOC % ((row - 1) * 35)).fill(value)
        self.page.locator(FilterPageLocator.CONDITION_BASE_FIELD_ARGS_LOC % ((row - 1) * 35)).press_sequentially(" ")
        self.page.locator(FilterPageLocator.CONDITION_BASE_ITEM_ARGS_LOC % value).press_sequentially(" ")

    def _set_text_area(self, row:int, value:str):
        """
        条件值字段，大文本字段类型赋值

        **用法：**

        FilterPage.set_text_area(1, "大文本字段值1234567890")

        使用FilterPage.set_condition_value()方法代替，此方法无需区分字段类型
        :param row: 行号，从1开始
        :param value: 条件值
        :return:
        """
        self.page.locator(FilterPageLocator.CONDITION_TEXTAREA_ARGS_LOC % ((row - 1) * 35)).fill(value)

    def set_logic(self, row:int, value:str):
        """
        设置逻辑符号，如并且

        **用法：**

        FilterPage.set_logic(1, "并且")
        :param row: 行号，从1开始
        :param value: 逻辑符号，取并且，或者
        :return:
        """
        self.page.locator(FilterPageLocator.LOGIC_ARGS_LOC % ((row - 1) * 35)).click()
        self.page.locator(FilterPageLocator.COMPARE_ITEM_ARGS_LOC % value).click()

    def _parse_condition_value_field_type(self, row:int) -> FieldType:
        """
        根据条件项元素属性，自动解析条件值项字段类型

        **用法：**

        FilterPage._parse_condition_value_field_type(1)

        **注意：**

        1.金蝶大版本升级后，判断依据可能会调整

        2.当前支持v8.2
        :param row: 行号，从1开始
        :return:
        """
        data_role = self.page.locator(FilterPageLocator.PARSE_CONDITION_VALUE_FIELD_TYPE_ARGS_LOC % ((row - 1) * 35)).get_attribute("data-attdata")
        pattern = "xtype\":\"([a-zA-Z0-9]+)"
        match_strs = re.findall(pattern, data_role)
        if match_strs:
            match match_strs[0]:
                case "textfield":
                    return FieldType.TEXT
                case "bosf7field":
                    return FieldType.BASE
                case "kdeditcombo" | "kdcombo":
                    return FieldType.SELECT
                case "kdmulticombo":
                    return FieldType.MULTISELECT
                case "kdtextarea" | "kdlangtextarea" | "kdtabpage":
                    return FieldType.TEXTAREA
                case "datefield":
                    return FieldType.DATE
        return FieldType.UNKNOWN
    def set_condition_value(self, row:int, value:str, field_type: FieldType = None):
        """
        条件值字段赋值，不给定字段类型时自动解析字段类型，推荐不给定，方便统一调用形式

        **用法：**

        FilterPage.set_condition_value(1, "26024001")

        FilterPage.set_condition_value(1, "26024001", FieldType.TEXT)

        :param row: 行号，从1开始
        :param value: 条件值
        :param field_type: 条件值字段类型，可选
        :return:
        """
        if field_type is None:
            field_type = self._parse_condition_value_field_type(row)
        match field_type:
            case FieldType.TEXT:
                self.set_text(row, value)
            case FieldType.SELECT:
                self.set_select(row, value)
            case FieldType.BASE:
                self.set_base(row, value)
            case FieldType.DATE:
                self.set_date(row, value)
            case FieldType.TEXTAREA:
                self.set_text_area(row, value)
            case _:
                raise TypeError("未匹配到过滤页面过滤条件输入框字段类型。")

    def click_ok_button(self):
        """
        点击确定，开始过滤

        **用法：**

        FilterPage.click_ok_button()
        :return:
        """
        self.page.locator(FilterPageLocator.FILTER_OK_BUTTON_LOC).click()

    def set_condition_row(self, row:int, condition_name:str, condition_value:str=None, operator:str=None, logic:str=None):
        """
        设置一行过滤条件

        **用法：**

        FilterPage.set_condition_row(1, "创建日期", operator="今天")

        FilterPage.set_condition_row(1, "衬衣订单号", "26024001")

        FilterPage.set_condition_row(1, "衬衣订单号", "26024", "包含")

        FilterPage.set_condition_row(1, "衬衣订单号", "26024", "包含", "或者")
        :param row: 行号，从1,开始
        :param condition_name: 过滤条件名
        :param condition_value: 过滤条件值，可选
        :param operator: 操作符，可选
        :param logic: 逻辑符，可选
        :return:
        """
        self.set_condition(row, condition_name)
        if operator:
            self.set_operator(row, operator)
        if condition_value:
            self.set_condition_value(row, condition_value)
        if logic:
            self.set_logic(row, logic)

    def filter(self, *condition_row: ConditionRow):
        """
        根据条件对象进行过滤，默认勾选全部组织

        **用法：**

        cond1 = ConditionRow(1, "基本信息-衬衣订单号", "123456", "包含", "或者")

        cond2 = ConditionRow(2, "单据状态", "已审核")

        FilterPage.filter(cond1, cond2)
        :param condition_row: 条件对象，ConditionRow(row:int, condition_name:str, condition_value:str=None, operator:str=None, logic:str=None), 可传多个
        :return:
        """
        self.check_all_org()
        self.click_tool_bar_button("全部删除")
        time.sleep(1)
        for cr in condition_row:
            self.set_condition_row(cr.row, cr.condition_name, cr.condition_value, cr.operator, cr.logic)
        self.click_ok_button()



