import pytest
import allure
import logging
import requests
import json
import time
from dulizhan.library.BusinessKw.JoyHub.ShippingTemplateManage import ShippingTemplateManage

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


@allure.feature("管理后台 - 运费模板模块")
class TestShippingTemplateManage:
    shipping_template_id = None
    token_set = False

    @classmethod
    def setup_class(cls):
        """在整个测试类开始时登录一次，所有测试用例共享token"""
        logging.info("=============================================")
        logging.info("=========== 开始登录，获取Token ============")
        logging.info("=============================================")

        cls.test_case = ShippingTemplateManage()
        username = "joytest"
        password = "Zhou1599"

        cls.test_case._clear_user_fingerprint(username)

        url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
        payload = {"username": username, "password": password}
        headers = {'Content-Type': 'application/json', 'tenant-id': '126'}

        try:
            response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
            login_response = response.json()

            if login_response and login_response.get('code') == 0:
                token = login_response.get('data', {}).get('accessToken', '')
                if token:
                    cls.test_case.set_joyhub_token(token)
                    cls.token_set = True
                    logging.info("登录成功，获取到Token: {}...".format(token[:20]))
                else:
                    logging.warning("登录成功但未获取到Token")
            else:
                logging.error("登录失败: {}".format(login_response))
        except Exception as e:
            logging.error("登录异常: {}".format(str(e)))

    def setup_method(self):
        """每个测试方法执行前检查token"""
        if not self.token_set:
            pytest.skip("Token未设置，跳过测试")

    @allure.story("验证登录接口")
    @allure.title("测试登录接口")
    def test_joyhub_login_post(self):
        """登录测试用例，验证登录接口是否正常"""
        with allure.step("1. 准备登录参数"):
            username = "joytest"
            password = "Zhou1599"
            allure.attach(f"用户名: {username}, 密码: {password}", name="登录参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用登录接口"):
            url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
            payload = {"username": username, "password": password}
            headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
            response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
            resp = response.json()
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="登录响应", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"登录失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert "accessToken" in resp["data"], "响应中缺少accessToken字段"
            logging.info("登录接口验证通过")

    @allure.story("验证获得运费模板分页列表")
    @allure.title("测试获得运费模板分页列表接口")
    def test_joyhub_shipping_template_page_get(self):
        """测试获得运费模板分页列表接口"""
        with allure.step("1. 准备请求参数"):
            params = {"page_no": 1, "page_size": 10}
            allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用接口"):
            resp = self.test_case.kw_joyhub_shipping_template_page_get(**params)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert "list" in resp["data"], "响应中缺少list字段"
            assert isinstance(resp["data"]["list"], list), "list字段不是数组类型"
            logging.info("获得运费模板分页列表接口验证通过")

    @allure.story("验证创建运费模板")
    @allure.title("测试创建运费模板接口")
    def test_joyhub_shipping_template_create_post(self):
        """测试创建运费模板接口"""
        with allure.step("1. 准备请求参数"):
            timestamp = int(time.time())
            params = {
                "template_name": f"测试模板_{timestamp}",
                "is_default": 2,
                "calculation_algorithm": "fixed_amount",
                "currency": "USD",
                "status": 1
            }
            allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用接口"):
            resp = self.test_case.kw_joyhub_shipping_template_create_post(**params)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert isinstance(resp["data"], int), "data字段不是整数类型"
            TestShippingTemplateManage.shipping_template_id = resp["data"]
            logging.info(f"创建运费模板成功，模板ID: {TestShippingTemplateManage.shipping_template_id}")

    @allure.story("验证获得运费模板详情")
    @allure.title("测试获得运费模板详情接口")
    def test_joyhub_shipping_template_get_detail_get(self):
        """测试获得运费模板详情（含规则与子表）接口"""
        if not TestShippingTemplateManage.shipping_template_id:
            pytest.skip("没有可用的运费模板ID，跳过测试")

        with allure.step("1. 准备请求参数"):
            shipping_template_id = TestShippingTemplateManage.shipping_template_id
            allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用接口"):
            resp = self.test_case.kw_joyhub_shipping_template_get_detail_get(shipping_template_id=shipping_template_id)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            logging.info("获得运费模板详情接口验证通过")

    @allure.story("验证保存运费模板（含规则与子表）")
    @allure.title("测试保存运费模板（含规则与子表）接口")
    def test_joyhub_shipping_template_save_with_children_post(self):
        """测试保存运费模板信息（含规则与子表）接口"""
        with allure.step("1. 准备请求参数"):
            timestamp = int(time.time())
            params = {
                "template_name": f"测试模板_含规则_{timestamp}",
                "is_default": 2,
                "calculation_algorithm": "fixed_amount",
                "currency": "USD",
                "status": 1,
                "shipping_rules": []
            }
            allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用接口"):
            resp = self.test_case.kw_joyhub_shipping_template_save_with_children_post(**params)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert isinstance(resp["data"], int), "data字段不是整数类型"
            logging.info(f"保存运费模板（含规则与子表）成功，模板ID: {resp['data']}")

    @allure.story("验证更新运费模板")
    @allure.title("测试更新运费模板接口")
    def test_joyhub_shipping_template_update_put(self):
        """测试更新运费模板接口"""
        with allure.step("1. 先创建一个测试运费模板"):
            timestamp = int(time.time())
            create_resp = self.test_case.kw_joyhub_shipping_template_create_post(
                template_name=f"待修改模板_{timestamp}",
                is_default=2,
                calculation_algorithm="fixed_amount",
                currency="USD",
                status=1
            )
            shipping_template_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None

            if not shipping_template_id:
                pytest.skip("创建测试运费模板失败，跳过更新测试")

            allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="待修改模板ID", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 准备修改参数"):
            params = {
                "id": shipping_template_id,
                "template_name": f"测试模板_修改_{timestamp}",
                "is_default": 2,
                "calculation_algorithm": "percentage",
                "currency": "CNY",
                "status": 2
            }
            allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)

        with allure.step("3. 调用更新接口"):
            resp = self.test_case.kw_joyhub_shipping_template_update_put(**params)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("4. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert resp["data"] is True, "更新运费模板失败"
            logging.info("更新运费模板接口验证通过")

    @allure.story("验证删除运费模板")
    @allure.title("测试删除运费模板接口")
    def test_joyhub_shipping_template_delete_post(self):
        """测试删除运费模板接口"""
        with allure.step("1. 先创建一个测试运费模板"):
            timestamp = int(time.time())
            create_resp = self.test_case.kw_joyhub_shipping_template_create_post(
                template_name=f"待删除模板_{timestamp}",
                is_default=2,
                calculation_algorithm="fixed_amount",
                currency="USD",
                status=1
            )
            shipping_template_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None

            if not shipping_template_id:
                pytest.skip("创建测试运费模板失败，跳过删除测试")

            allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="待删除模板ID", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 先停用模板（启用的不能删）"):
            update_resp = self.test_case.kw_joyhub_shipping_template_update_put(
                id=shipping_template_id,
                template_name=f"待删除模板_{timestamp}",
                is_default=2,
                calculation_algorithm="fixed_amount",
                currency="USD",
                status=2
            )
            if update_resp.get("code") != 0:
                pytest.skip("停用模板失败，跳过删除测试")
            logging.info(f"已停用模板 {shipping_template_id}")

        with allure.step("3. 调用删除接口"):
            resp = self.test_case.kw_joyhub_shipping_template_delete_post(shipping_template_id=shipping_template_id)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("4. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert resp["data"] is True, "删除运费模板失败"
            logging.info("删除运费模板接口验证通过")

    @allure.story("验证批量删除运费模板")
    @allure.title("测试批量删除运费模板接口")
    def test_joyhub_shipping_template_delete_list_post(self):
        """测试批量删除运费模板接口"""
        with allure.step("1. 先创建两个测试运费模板"):
            timestamp = int(time.time())
            resp1 = self.test_case.kw_joyhub_shipping_template_create_post(
                template_name=f"批量删除模板1_{timestamp}",
                is_default=2,
                calculation_algorithm="fixed_amount",
                currency="USD",
                status=1
            )
            resp2 = self.test_case.kw_joyhub_shipping_template_create_post(
                template_name=f"批量删除模板2_{timestamp}",
                is_default=2,
                calculation_algorithm="fixed_amount",
                currency="USD",
                status=1
            )

            template_id_1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
            template_id_2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None

            if not template_id_1 or not template_id_2:
                pytest.skip("创建测试运费模板失败，跳过批量删除测试")

            ids = [template_id_1, template_id_2]
            allure.attach(json.dumps({"ids": ids}, ensure_ascii=False), name="待删除模板ID", attachment_type=allure.attachment_type.TEXT)

        with allure.step("2. 调用批量删除接口"):
            resp = self.test_case.kw_joyhub_shipping_template_delete_list_post(ids=ids)
            allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)

        with allure.step("3. 验证响应"):
            assert resp is not None, "响应为空"
            assert "code" in resp, "响应中缺少code字段"
            assert resp["code"] == 0, f"请求失败，code={resp.get('code')}"
            assert "data" in resp, "响应中缺少data字段"
            assert resp["data"] is True, "批量删除运费模板失败"
            logging.info("批量删除运费模板接口验证通过")