import allure
import pytest

from src.book import BookManagement
from utils.utils import Utils


# 缓存 YAML 数据，避免重复读取
_yaml_data = None

def _get_yaml_data():
    '''
    读取 YAML 数据
    '''
    global _yaml_data
    if _yaml_data is None:
        _yaml_data = Utils.get_yaml_data("E:/霍格沃兹测试/test/book_project/datas/book_info.yaml")
    return _yaml_data

def get_add_cases():
    '''
    获取添加图书的测试数据
    '''
    cases = _get_yaml_data().get("add", {}).get("cases", [])
    return [(case["data"], case["expected"]) for case in cases]

def get_add_ids():
    '''
    获取添加图书的测试用例名称
    '''
    cases = _get_yaml_data().get("add", {}).get("cases", [])
    return [case["id"] for case in cases]


def _get_successful_books():
    '''
    提取添加成功的图书
    '''
    add_cases = _get_yaml_data().get("add", {}).get("cases", [])
    books = []
    for case in add_cases:
        if case["expected"] == "返回成功结果":
            data = case["data"]
            books.append({
                "bid": data[0],
                "name": data[1]
            })

    return books

def get_query_by_bid_cases():
    '''
    获取 by_bid 查询的测试数据
    :return:
    '''
    cases = []

    # 添加成功的 bid
    book = _get_successful_books()[0]
    cases.append(([book["bid"]], "返回成功结果"))

    # 异常用例
    query_cases = _get_yaml_data().get("query", {}).get("by_bid", {}).get("cases", [])
    for case in query_cases:
        cases.append((case["data"], case["expected"]))

    return cases

def get_query_by_bid_ids():
    '''
    获取 by_bid 查询的测试用例名
    :return:
    '''

    book = _get_successful_books()[0]
    ids = [f"query_bid_{book['bid']}"]

    query_cases = _get_yaml_data().get("query", {}).get("by_bid", {}).get("cases", [])
    ids.extend([case["id"] for case in query_cases])
    return ids

def get_query_by_name_cases():
    '''
    获取 by_name 查询的测试数据
    :return:
    '''
    cases = []

    # 添加成功的 name
    book = _get_successful_books()[0]
    cases.append(([book["name"]], "返回成功结果"))

    # 异常用例
    query_cases = _get_yaml_data().get("query", {}).get("by_name", {}).get("cases", [])
    for case in query_cases:
        cases.append((case["data"], case["expected"]))

    return cases

def get_query_by_name_ids():
    '''
    获取 by_name 查询的测试用例名
    :return:
    '''

    book = _get_successful_books()[0]
    ids = [f"query_name_{book['bid']}"]
    query_cases = _get_yaml_data().get("query", {}).get("by_name", {}).get("cases", [])
    ids.extend([case["id"] for case in query_cases])
    return ids


def get_delete_by_bid_cases():
    '''
    获取 by_bid 删除的测试数据
    :return:
    '''
    cases = []
    # 添加成功的 bid
    book = _get_successful_books()[0]
    cases.append(([book["bid"]], "返回成功结果"))

    # 异常用例
    query_cases = _get_yaml_data().get("delete", {}).get("by_bid", {}).get("cases", [])
    for case in query_cases:
        cases.append((case["data"], case["expected"]))

    return cases

def get_delete_by_bid_ids():
    '''
    获取 by_bid 删除的测试用例名
    :return:
    '''
    book = _get_successful_books()[0]
    ids = [f"delete_id_{book['bid']}"]
    query_cases = _get_yaml_data().get("delete", {}).get("by_bid", {}).get("cases", [])
    ids.extend([case["id"] for case in query_cases])
    return ids

def get_delete_by_name_cases():
    '''
    获取 by_name 删除的测试用数据
    :return:
    '''
    cases = []

    # 添加成功的 name
    book = _get_successful_books()[0]
    cases.append(([book['name']],"返回成功结果"))

    # 异常用例
    query_cases = _get_yaml_data().get("delete", {}).get("by_name", {}).get("cases", [])
    for case in query_cases:
        cases.append((case["data"], case["expected"]))

    return cases

def get_delete_by_name_ids():
    '''
    获取 by_name 删除的测试用例名
    :return:
    '''
    book = _get_successful_books()[0]
    ids = [f"delete_name_{book['bid']}"]
    query_cases = _get_yaml_data().get("delete", {}).get("by_name", {}).get("cases", [])
    ids.extend([case["id"] for case in query_cases])
    return ids


@allure.feature("测试图书管理系统")
class TestBookManagement():

    def setup_class(self):
        '''
        前置处理方法
        '''
        self.bm = BookManagement()

    def teardown_class(self):
        '''
        后置处理
        '''
        print("class最后执行的方法")

    @allure.story("图书管理")
    @allure.title("添加图书")
    @pytest.mark.P0
    @pytest.mark.parametrize(
        "data, expected",
        get_add_cases(),
        ids=get_add_ids()
    )
    def test_add_book(self,data,expected):
        '''
        参数化添加图书信息
        :return:
        '''
        bid, name, price, summary = data
        with allure.step("调用添加学生方法"):
            result = self.bm.add_book(bid, name, price, summary)
        with allure.step("断言结果"):
            assert expected == result

    @allure.story("图书查询")
    @allure.title("根据ID查询图书")
    @pytest.mark.P0
    @pytest.mark.parametrize(
        "data,expected",
        get_query_by_bid_cases(),
        ids=get_query_by_bid_ids()
    )
    def test_query_id_book(self,data,expected):
        '''
        通过ID查询图书
        :param data:
        :param expected:
        :return:
        '''
        bid = data[0]
        with allure.step("调用通过ID查询学生方法"):
            result = self.bm.query_book_by_id(bid)
        with allure.step("断言结果"):
            assert expected == result

    @allure.story("图书查询")
    @allure.title("根据书名查询图书")
    @pytest.mark.P0
    @pytest.mark.parametrize(
        "data,expected",
        get_query_by_name_cases(),
        ids=get_query_by_name_ids()
    )
    def test_query_name_book(self,data,expected):
        '''
        通过 name 查询图书
        :param data:
        :param expected:
        :return:
        '''
        name = data[0]
        with allure.step("调用通过name查询学生方法"):
            result = self.bm.query_book_by_name(name)
        with allure.step("断言结果"):
            assert expected == result

    @allure.story("图书管理")
    @allure.title("根据ID删除图书")
    @pytest.mark.P0
    @pytest.mark.parametrize(
        "data,expected",
        get_delete_by_bid_cases(),
        ids=get_delete_by_bid_ids()
    )
    def test_delete_bid_book(self,data,expected):
        '''
        按照 id 删除图书
        :param data:
        :param expected:
        :return:
        '''
        bid = data[0]
        with allure.step("调用通过ID删除学生方法"):
            result = self.bm.delete_book_by_id(bid)
        with allure.step("断言结果"):
            assert expected == result

    @allure.story("图书管理")
    @allure.title("根据书名删除图书")
    @pytest.mark.P0
    @pytest.mark.parametrize(
        "data,expected",
        get_delete_by_name_cases(),
        ids=get_delete_by_name_ids()
    )
    def test_delete_name_book(self,data,expected):
        '''
        通过 name 删除图书
        :param data:
        :param expected:
        :return:
        '''
        name = data[0]
        with allure.step("调用通过name删除学生方法"):
            result = self.bm.delete_book_by_name(name)
        with allure.step("断言结果"):
            assert expected == result