"""
施工方案审查API错误码测试 - pytest版本
使用pytest运行的标准测试套件
"""

import pytest
import requests
import json
import uuid
import time
import os
from typing import Dict, Any

# pytest fixtures
@pytest.fixture(scope="class")
def api_config():
    """API配置fixture"""
    return {
        "base_url": "http://127.0.0.1:8034",
        "api_prefix": "/sgsc",
        "valid_user": "user-001",
        "valid_project_type": "bridge_up_part",
        "test_callback_url": "http://test.callback.com"
    }

@pytest.fixture
def test_file():
    """测试文件fixture - 每个测试都创建新的文件对象"""
    file_path = "data_pipeline/test_rawdata/1f3e1d98-5b4a-4a06-87b3-c7f0413b901a.pdf"

    class TestFile:
        def __init__(self):
            if os.path.exists(file_path):
                self.file = open(file_path, 'rb')
                self.file_tuple = (os.path.basename(file_path), self.file, 'application/pdf')
                self.close_file = True
            else:
                self.file = None
                self.file_tuple = ("test.pdf", b"mock pdf content", "application/pdf")
                self.close_file = False

        def get_file(self):
            """获取文件元组"""
            if self.close_file and self.file:
                # 重新打开文件，确保文件未被关闭
                self.file.seek(0)
            return self.file_tuple

        def cleanup(self):
            """清理资源"""
            if self.close_file and self.file:
                self.file.close()

    test_file_obj = TestFile()
    yield test_file_obj
    test_file_obj.cleanup()

class TestFileUploadErrors:
    """文件上传接口错误码测试"""

    @pytest.mark.parametrize("test_case,expected_code", [
        ("missing_file", "WJSC001"),
        ("empty_file", "WJSC003"),
        ("unsupported_format", "WJSC004"),
        ("invalid_project_type", "WJSC006")
    ])
    def test_file_upload_errors(self, api_config, test_case, expected_code):
        """测试文件上传各种错误场景"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/file_upload"

        if test_case == "missing_file":
            # 不上传文件
            data = {
                "callback_url": api_config["test_callback_url"],
                "project_plan_type": api_config["valid_project_type"],
                "user": api_config["valid_user"]
            }
            response = requests.post(url, data=data)

        elif test_case == "empty_file":
            # 上传空文件
            files = {"file": ("empty.pdf", b"", "application/pdf")}
            data = {
                "callback_url": api_config["test_callback_url"],
                "project_plan_type": api_config["valid_project_type"],
                "user": api_config["valid_user"]
            }
            response = requests.post(url, files=files, data=data)

        elif test_case == "unsupported_format":
            # 上传不支持的格式
            files = {"file": ("test.txt", b"text content", "text/plain")}
            data = {
                "callback_url": api_config["test_callback_url"],
                "project_plan_type": api_config["valid_project_type"],
                "user": api_config["valid_user"]
            }
            response = requests.post(url, files=files, data=data)

        elif test_case == "invalid_project_type":
            # 无效的工程方案类型
            files = {"file": ("test.pdf", b"mock pdf content", "application/pdf")}
            data = {
                "callback_url": api_config["test_callback_url"],
                "project_plan_type": "invalid_type",
                "user": api_config["valid_user"]
            }
            response = requests.post(url, files=files, data=data)

        # 验证错误响应
        assert response.status_code in [400, 403, 404]  # 允许的业务错误状态码

        try:
            error_data = response.json()
            assert error_data["code"] == expected_code
            assert "error_type" in error_data
            assert "message" in error_data
        except json.JSONDecodeError:
            pytest.fail(f"响应不是有效的JSON: {response.text}")

    def test_file_upload_success(self, api_config, test_file):
        """测试文件上传成功"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/file_upload"
        files = {"file": test_file.get_file()}
        data = {
            "callback_url": api_config["test_callback_url"],
            "project_plan_type": api_config["valid_project_type"],
            "user": api_config["valid_user"]
        }

        response = requests.post(url, files=files, data=data)
        assert response.status_code == 200

        result = response.json()
        assert "data" in result
        assert "callback_task_id" in result["data"]
        assert "id" in result["data"]

    @pytest.mark.skip(reason="文件大小检查未实现")
    def test_wjsc005_file_size_exceeded(self, api_config):
        """测试WJSC005: 文件过大 - 跳过因为未实现"""
        pass

    @pytest.mark.skip(reason="认证检查未实现")
    def test_wjsc007_unauthorized(self, api_config):
        """测试WJSC007: 认证失败 - 跳过因为未实现"""
        pass


class TestTaskProgressErrors:
    """进度查询接口错误码测试"""

    def test_jdlx001_missing_parameters(self, api_config):
        """测试JDLX001: 请求参数缺失"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/task_progress/test-callback-id"
        response = requests.get(url)  # 不提供user参数

        assert response.status_code == 400
        error_data = response.json()
        assert error_data["code"] == "JDLX001"

    @pytest.mark.parametrize("invalid_id", ["short", "123", "invalid-format"])
    def test_jdlx002_invalid_param_format(self, api_config, invalid_id):
        """测试JDLX002: 请求参数格式错误"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/task_progress/{invalid_id}"
        params = {"user": api_config["valid_user"]}

        response = requests.get(url, params=params)
        assert response.status_code == 400

        error_data = response.json()
        assert error_data["code"] == "JDLX002"

    @pytest.mark.parametrize("invalid_user", ["invalid_user", "user-999", ""])
    def test_jdlx004_invalid_user(self, api_config, test_file, invalid_user):
        """测试JDLX004: 用户标识无效"""
        # 先上传文件获取有效的callback_task_id
        callback_task_id = self._upload_file_and_get_callback(api_config, test_file)

        url = f"{api_config['base_url']}{api_config['api_prefix']}/task_progress/{callback_task_id}"
        params = {"user": invalid_user}

        response = requests.get(url, params=params)
        assert response.status_code == 403

        error_data = response.json()
        assert error_data["code"] == "JDLX004"

    def test_jdlx005_task_not_found(self, api_config):
        """测试JDLX005: 任务不存在"""
        fake_callback_id = f"{uuid.uuid4()}-{int(time.time())}"
        url = f"{api_config['base_url']}{api_config['api_prefix']}/task_progress/{fake_callback_id}"
        params = {"user": api_config["valid_user"]}

        response = requests.get(url, params=params)
        assert response.status_code == 404

        error_data = response.json()
        assert error_data["code"] == "JDLX005"

    def _upload_file_and_get_callback(self, api_config, test_file):
        """辅助方法：上传文件并获取callback_task_id"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/file_upload"
        files = {"file": test_file.get_file()}
        data = {
            "callback_url": api_config["test_callback_url"],
            "project_plan_type": api_config["valid_project_type"],
            "user": api_config["valid_user"]
        }

        response = requests.post(url, files=files, data=data)
        assert response.status_code == 200
        result = response.json()
        return result["data"]["callback_task_id"]

    @pytest.mark.skip(reason="认证检查未实现")
    def test_jdlx003_unauthorized(self, api_config):
        """测试JDLX003: 认证失败 - 跳过因为未实现"""
        pass


class TestReviewResultsErrors:
    """审查结果接口错误码测试"""

    @pytest.mark.parametrize("invalid_type", ["invalid", "risk", "detail", ""])
    def test_scjg001_invalid_type(self, api_config, invalid_type):
        """测试SCJG001: 结果类型无效"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/review_results"
        payload = {
            "id": str(uuid.uuid4()),
            "user": api_config["valid_user"],
            "type": invalid_type
        }

        response = requests.post(url, json=payload)
        assert response.status_code == 400

        error_data = response.json()
        assert error_data["code"] == "SCJG001"

    @pytest.mark.parametrize("invalid_id", ["", None])
    def test_scjg002_missing_param_id(self, api_config, invalid_id):
        """测试SCJG002: 缺少文档ID"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/review_results"

        if invalid_id is None:
            payload = {
                "user": api_config["valid_user"],
                "type": "summary"
            }
        else:
            payload = {
                "id": invalid_id,
                "user": api_config["valid_user"],
                "type": "summary"
            }

        response = requests.post(url, json=payload)
        assert response.status_code == 400

        error_data = response.json()
        assert error_data["code"] == "SCJG002"

    @pytest.mark.parametrize("invalid_format", ["123", "short-id", "invalid-uuid-format"])
    def test_scjg003_invalid_id_format(self, api_config, invalid_format):
        """测试SCJG003: 文档ID格式错误"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/review_results"
        payload = {
            "id": invalid_format,
            "user": api_config["valid_user"],
            "type": "summary"
        }

        response = requests.post(url, json=payload)
        assert response.status_code == 400

        error_data = response.json()
        assert error_data["code"] == "SCJG003"

    def test_scjg005_invalid_user_review_results(self, api_config, test_file):
        """测试SCJG005: 用户标识无效（审查结果接口）"""
        # 先上传文件获取有效的文件ID
        file_id = self._upload_file_and_get_file_id(api_config, test_file)

        url = f"{api_config['base_url']}{api_config['api_prefix']}/review_results"
        payload = {
            "id": file_id,
            "user": "invalid_user",
            "type": "summary"
        }

        response = requests.post(url, json=payload)
        assert response.status_code == 403

        error_data = response.json()
        assert error_data["code"] == "SCJG005"

    def test_scjg006_task_not_found_review_results(self, api_config):
        """测试SCJG006: 任务不存在（审查结果接口）"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/review_results"
        payload = {
            "id": str(uuid.uuid4()),
            "user": api_config["valid_user"],
            "type": "summary"
        }

        response = requests.post(url, json=payload)
        assert response.status_code == 404

        error_data = response.json()
        assert error_data["code"] == "SCJG006"

    def _upload_file_and_get_file_id(self, api_config, test_file):
        """辅助方法：上传文件并获取文件ID"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/file_upload"
        files = {"file": test_file.get_file()}
        data = {
            "callback_url": api_config["test_callback_url"],
            "project_plan_type": api_config["valid_project_type"],
            "user": api_config["valid_user"]
        }

        response = requests.post(url, files=files, data=data)
        assert response.status_code == 200
        result = response.json()
        return result["data"]["id"]

    @pytest.mark.skip(reason="认证检查未实现")
    def test_scjg004_unauthorized(self, api_config):
        """测试SCJG004: 认证失败 - 跳过因为未实现"""
        pass


class TestIntegration:
    """集成测试"""

    def test_complete_workflow_success(self, api_config, test_file):
        """测试完整工作流程成功场景"""
        # 1. 文件上传
        callback_task_id = self._upload_file_and_get_callback(api_config, test_file)
        assert callback_task_id is not None

        # 2. 进度查询
        url = f"{api_config['base_url']}{api_config['api_prefix']}/task_progress/{callback_task_id}"
        params = {"user": api_config["valid_user"]}
        response = requests.get(url, params=params)
        assert response.status_code == 200

    def _upload_file_and_get_callback(self, api_config, test_file):
        """辅助方法：上传文件并获取callback_task_id"""
        url = f"{api_config['base_url']}{api_config['api_prefix']}/file_upload"
        files = {"file": test_file.get_file()}
        data = {
            "callback_url": api_config["test_callback_url"],
            "project_plan_type": api_config["valid_project_type"],
            "user": api_config["valid_user"]
        }

        response = requests.post(url, files=files, data=data)
        assert response.status_code == 200
        result = response.json()
        return result["data"]["callback_task_id"]


if __name__ == "__main__":
    # 如果直接运行此文件，给出提示
    print("请使用 pytest 运行此测试文件:")
    print("pytest test/construction_review/test_error_codes_pytest.py -v")
    print("或者运行所有测试:")
    print("pytest test/ -v")