#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
@File    :   head_page.py
@Time    :   2024/11/07 15:19:33
@Author  :   dulip3ng 
@Version :   1.0
@Desc    :   None
'''

import re

from playwright.sync_api import Page, expect, Error
from pages.base_page import BasePage
from pages.locator.head_page_locator import HeadPageLocator
from common.field_type import FieldType

class HeadPage(BasePage):

    def click_button(self, button_name:str, sub_button_name:str=None):
        """
        点击单据头按钮
        :param button_name: 按钮名称
        :param sub_button_name: 子按钮名称
        :return: None
        """
        if not sub_button_name:
            self.page.locator(HeadPageLocator.BUTTON_ARGS_LOC % button_name).click()
        else:
            self.page.locator(HeadPageLocator.BUTTON_ARROW_ARGS_LOC % button_name).hover()
            self.page.locator(HeadPageLocator.SUB_BUTTON_ARGS_LOC % sub_button_name).click()

    def change_sheet(self, sheet_name:str):
        """
        点击单据头页签
        :param sheet_name: 页签名称
        :return: None
        """
        self.page.locator(HeadPageLocator.SHEET_ARGS_LOC % sheet_name).click()

    def _set_text(self, field_name:str, value:str):
        """
        单据头文本字段赋值
        :param field_name: 字段名
        :param value: 字段值
        :return: None
        """
        self.page.locator(HeadPageLocator.TEXT_FIELD_ARGS_LOC % field_name).fill(value)

    def _set_base(self, field_name:str, value:str):
        """
        单据头基础资料字段赋值
        :param field_name: 字段名
        :param value: 字段值
        :return: None
        """
        # 直接点击BASE_FIELD_ARGS_LOC input元素可操作性检查不通过，被BASE_FIELD_SPAN_ARGS_LOC span劫持，这里直接对span进行点击
        self.page.locator(HeadPageLocator.BASE_FIELD_SPAN_ARGS_LOC % field_name).click()
        self.page.locator(HeadPageLocator.BASE_FIELD_ARGS_LOC % field_name).fill(value)
        # 输入空格弹出基础资料选项，fill方法会覆盖当前输入内容，使用press_sequentially方法模拟输入
        self.page.locator(HeadPageLocator.BASE_FIELD_ARGS_LOC % field_name).press_sequentially(" ")
        self.page.locator(HeadPageLocator.BASE_ITEM_ARGS_LOC % value).click()

    def _set_select(self, field_name:str, item_value:str):
        """
        单据头下拉列表字段赋值
        :param field_name: 字段名
        :param item_value: 字段值
        :return: None
        """
        # Locator.click()普通点击无法弹出下拉选项值，使用force强制点击
        # 注意：force=True强制点击不执行非必要的元素可操作性检查
        self.page.locator(HeadPageLocator.SELECT_FIELD_ARGS_LOC % field_name).click(force=True)
        self.page.locator(HeadPageLocator.SELECT_ITEM_ARGS_LOC % item_value).click()

    def _set_textarea(self, field_name:str, value:str):
        """
        单据头大文本框字段赋值
        :param field_name: 字段名
        :param value: 字段值
        :return: None
        """
        self.page.locator(HeadPageLocator.TEXTAREA_FIELD_ARGS_LOC % field_name).fill(value)

    def _set_multiselect(self, field_name:str, values:str):
        """
        单据头多选下拉列表字段赋值
        :param field_name: 字段名
        :param values: 字段值
        :return: None
        """
        self.page.locator(HeadPageLocator.MULTISELECT_FIELD_ARGS_LOC % field_name).click()
        for item_value in values:
            self.page.locator(HeadPageLocator.MULTISELECT_ITEM_ARGS_LOC % item_value).click()
        self.page.locator(HeadPageLocator.MULTISELECT_OK_BTN_LOC).click()

    def set_value(self, field_name:str, *values:str, field_type: FieldType = None):
        """
        单据头字段赋值统一方法，根据给定或自动识别的字段类型调用不同方法完成赋值
        :param field_name: 字段名
        :param value: 字段值
        :param field_type: 可选参数，字段类型，不填时自动识别字段类型
        :return: None
        """
        if not field_type:
            field_type = self.parse_field_type(field_name)

        match field_type:
            case FieldType.TEXT:
                self._set_text(field_name, values[0])
            case FieldType.SELECT:
                self._set_select(field_name, values[0])
            case FieldType.BASE:
                self._set_base(field_name, values[0])
            case FieldType.TEXTAREA:
                self._set_textarea(field_name, values[0])
            case FieldType.MULTISELECT:
                self._set_multiselect(field_name, values)

    def set_checked(self, field_name:str):
        """
        单据头勾选复选框
        :param field_name: 复选框名
        :return: None
        """
        self.page.locator(HeadPageLocator.CHECKBOX_FIELD_ARGS_LOC % field_name).click()

    def set_text_in_head_body(self, field_name:str, value:str, row:int):
        """
        单据头中的单据体文本字段赋值
        如样品通知单-接收人页签
        :param field_name: 字段名
        :param value: 字段值
        :param row: 行号，从1开始
        :return: None
        """
        self.page.locator(HeadPageLocator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row-1)).click()
        self.page.locator(HeadPageLocator.TEXT_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row-1)).fill(value)

    def set_base_in_head_body(self, field_name:str, value:str, row: int):
        """
        单据头中的单据体基础资料字段赋值
        如样品通知单-接收人页签
        :param field_name: 字段名
        :param value: 字段值
        :param row: 行号，从1开始
        :return: None
        """
        self.page.locator(HeadPageLocator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row - 1)).click()
        self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).click()
        self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).fill(value)
        # 输入空格弹出基础资料选项，fill方法会覆盖当前输入内容，使用press_sequentially方法模拟输入
        self.page.locator(HeadPageLocator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)).press_sequentially(" ")
        self.page.locator(HeadPageLocator.BASE_ITEM_ARGS_LOC % value).click()


    def _get_text_value(self, field_name:str) -> str:
        """
        单据头文本字段取值
        文本字段有两种形式，一种是可编辑状态，值存放在input元素中，另一种是锁定状态值存放在span元素中，
        默认取input值，500ms超时未取到时取span中的值
        :param field_name: 字段名
        :return: 字段值
        """
        try:
            locator_input = self.page.locator(HeadPageLocator.TEXT_VALUE_INPUT_ARGS_LOC % field_name)
            expect(locator_input).to_be_visible(timeout=500)
            return locator_input.input_value()
        except AssertionError:
            locator_span = self.page.locator(HeadPageLocator.TEXT_VALUE_SPAN_ARGS_LOC % field_name)
            expect(locator_span).to_be_visible(timeout=500)
            return locator_span.inner_text()

    def _get_select_value(self, field_name:str) -> str:
        """
        单据头下拉列表字段取值
        下拉列表字段有两种形式，一种是可编辑状态，值存放在input元素中，另一种是锁定状态值存放在span元素中，
        默认取input值，未找到时立即去span中的值
        与取text不同的是text由两个xpath语句获取值，select由一个通用的xpath取值，所以判断方式不同
        :param field_name: 字段名
        :return: 字段值
        """
        try:
            locator = self.page.locator(HeadPageLocator.SELECT_VALUE_ARGS_LOC % field_name)
            return locator.input_value()
        except Error:
            return locator.inner_text()
    def _get_base_value(self, field_name:str) -> str:
        """
        获取单据头基础资料字段值
        :param field_name: 字段名
        :return: 字段值
        """
        return self.page.locator(HeadPageLocator.BASE_VALUE_ARGS_LOC % field_name).inner_text()

    def _get_textarea_value(self, field_name:str):
        """
        单据头大文本字段取值
        :param field_name: 字段名
        :return: 字段值
        """
        return self.page.locator(HeadPageLocator.TEXTAREA_FIELD_ARGS_LOC % field_name).input_value()

    def _get_multiselect_value(self, field_name:str):
        """
        单据头多选下拉列表字段取值
        :param field_name: 字段名
        :return: 字段值
        """
        return self.page.locator(HeadPageLocator.MULTISELECT_VALUE_ARGS_LOC % field_name).inner_text()

    def get_value(self, field_name:str, field_type: FieldType=None) -> str:
        """
        单据头字段取值统一方法，根据给定或自动识别的字段类型调用不同取值方法取值
        :param field_name: 字段名
        :param field_type: 可选参数，字段类型
        :return: 字段值
        """
        if not field_type:
            field_type = self.parse_field_type(field_name)

        match field_type:
            case FieldType.TEXT:
                return self._get_text_value(field_name)
            case FieldType.SELECT:
                return self._get_select_value(field_name)
            case FieldType.BASE:
                return self._get_base_value(field_name)
            case FieldType.MULTISELECT:
                return self._get_multiselect_value(field_name)
            case FieldType.TEXTAREA:
                return self._get_textarea_value(field_name)
            case _:
                return ""


    def _parse_field_type(self, field_name:str) -> FieldType:
        """
        分析字段类型，set_value(), get_value()中调用的核心方法
        注意：金蝶版本升级后可能不同字段类型判断依据有变化，字段类型是根据元素"data-attdata"属性值判断，
        定位器可用性检查通过不代表分析字段类型可正常使用
        :param field_name: 字段名
        :return: 字段类型 FieldType
        """
        data_role = self.page.locator(HeadPageLocator.PARSE_FIELD_TYPE_ARGS_LOC % field_name).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 "bosf7field":
                    return FieldType.BASE
                case "kdeditcombo" | "kdcombo":
                    return FieldType.SELECT
                case "kdmulticombo":
                    return FieldType.MULTISELECT
                case "kdtextarea" | "kdlangtextarea" | "kdtabpage":
                    return FieldType.TEXTAREA
                case _:
                    return FieldType.TEXT
        return FieldType.UNKNOWN

