# -*- coding: utf-8 -*-
# @Time    : 2021/4/14 18:59
# @Author  : wangyinghao
# @FileName: api_business_test_view.py
# @Software: PyCharm
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View
import json
import ast
import re
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_project import APIProject
from automated_main.models.api_automation.api_module import APIModule
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_business_test import ApiBusinessTest, ApiBusinessTestAssociated
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.handle_db import HandleDB
from automated_main.form.api_business_test import ApiBusinessTestForm
from automated_main.utils.api_utils import RegularMatch, InterfaceRequest, ExtractParameters
from automated_main.models.api_automation.api_test_case import ApiTestCase, ApiParameterExtraction, ApiParameterData

import logging

logger = logging.getLogger('django')


class GetApiBusinessTestSelectData(View):
    def get(self, request, api_project_id, *args, **kwargs):
        """
        获取api项目---模块---测试用例
        :param request:
        :param api_project_id: Api项目id
        :param args:
        :param kwargs:
        :return:
        """
        api_projects = APIProject.objects.filter(id=api_project_id)
        data_list = []
        for api_project in api_projects:
            project_dict = {
                "project_id": api_project.id,
                "api_project_name": api_project.api_project_name
            }

            api_modules = APIModule.objects.filter(api_project_id=api_project.id)
            api_module_list = []
            for api_module in api_modules:
                api_test_cases = ApiTestCase.objects.filter(api_module_id=api_module.id)
                api_test_case_list = []
                for api_test_case in api_test_cases:
                    api_test_case_list.append({
                        "api_test_case_id": api_test_case.id,
                        "api_test_case_name": api_test_case.api_test_case_name,

                    })

                api_module_list.append({
                    "api_module_id": api_module.id,
                    "api_module_name": api_module.api_module_name,
                    "api_test_case_list": api_test_case_list,
                })

            project_dict["module_list"] = api_module_list

            data_list.append(project_dict)

        return response_success(data_list)


class ApiBusinessTestView(View):
    def delete(self, request, api_business_test_id, *args, **kwargs):
        """
        代表删除API业务测试
        :param request:
        :param api_business_test_id: 业务测试id
        :param args:
        :param kwargs:
        :return:
        """
        ApiBusinessTest.objects.get(id=api_business_test_id).delete()
        return response_success("删除API业务测试成功")

    def get(self, request, api_business_test_id, *args, **kwargs):
        """
        获取单独API业务测试
        :param request:
        :param api_business_test_id: 业务测试ID
        :param args:
        :param kwargs:
        :return:
        """

        api_business_test = ApiBusinessTest.objects.get(id=api_business_test_id)
        api_business_test_associated = ApiBusinessTestAssociated.objects.filter(bid_id=api_business_test_id)

        if api_business_test is None:
            return response_success()
        else:
            api_business_test_data_list = []
            for api_business_test_associateds in api_business_test_associated:
                api_business_test_dict = {
                    "api_module_id": api_business_test_associateds.api_module_id,
                    "api_test_case_id": api_business_test_associateds.api_test_case_id,
                    "steps": int(api_business_test_associateds.case_steps),
                }
                api_business_test_data_list.append(api_business_test_dict)
            api_business_test_data_list_sorting = sorted(api_business_test_data_list, key=lambda x: x['steps'])

            return response_success({"api_business_test_name": api_business_test.api_business_test_name,
                                     "api_project_id": api_business_test.api_project_id,
                                     "api_business_test_describe": api_business_test.api_business_test_describe,
                                     "api_business_test_data": api_business_test_data_list_sorting})

    def post(self, request, api_business_test_id, *args, **kwargs):
        """
        编辑API业务测试
        :param request:
        :param api_business_test_id:
        :param args:
        :param kwargs:
        :return:
        """
        api_business_test = ApiBusinessTest.objects.get(id=api_business_test_id)
        if api_business_test is None:
            return response_success()
        body = request.body
        if not body:
            return response_success()
        data = json.loads(body)
        form = ApiBusinessTestForm(data)

        api_business_test.api_business_test_name = data['api_business_test_name']
        api_business_test.api_project.id = data['api_project_id']
        api_business_test.id = data['api_business_test_id']
        api_business_test.api_business_test_describe = data['api_business_test_describe']
        api_business_test.save()
        ApiBusinessTestAssociated.objects.filter(bid_id=api_business_test_id).delete()

        if form.is_valid():
            for i in data["api_business_test_data"]:
                api_module_id = (i['api_module_id'])
                api_test_case_id = (i['api_test_case_id'])
                case_steps = (i['steps'])

                ApiBusinessTestAssociated.objects.create(bid_id=api_business_test_id, api_module_id=api_module_id,
                                                         api_test_case_id=api_test_case_id, case_steps=case_steps)
            return response_success("编辑API业务测试")
        else:
            raise MyException()

    def put(self, request, *args, **kwargs):
        """
        创建API业务测试
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        body = request.body
        if not body:
            return response_success()
        data = json.loads(body)
        form = ApiBusinessTestForm(data)
        if form.is_valid():
            api_business_test = ApiBusinessTest.objects.create(**form.cleaned_data)
            api_business_test_id = api_business_test.id

            for i in data["api_business_test_data"]:
                api_module_id = (i['api_module_id'])
                api_test_case_id = (i['api_test_case_id'])
                case_steps = (i['steps'])
                ApiBusinessTestAssociated.objects.create(bid_id=api_business_test_id, api_module_id=api_module_id,
                                                         api_test_case_id=api_test_case_id, case_steps=case_steps)

            return response_success("创建API业务测试用例成功")
        else:
            raise MyException()


class ApiBusinessTestDebugView(View):

    def post(self, request, *args, **kwargs):
        """
        API业务测试DEBUG
        :param request:
        :param args:
        :param kwargs:
        :return:
        """

        body = request.body
        if not body:
            return response_success()
        data = json.loads(body)
        for case in data['api_business_test_data']:
            test_case = ApiTestCase.objects.get(id=case['api_test_case_id'])

            api_environment = APIEnvironment.objects.get(id=data['environment'])
            # 请求地址
            api_url = api_environment.api_title + test_case.api_url

            api_url = RegularMatch(api_url, data['environment'])
            if api_url[0] == "该变量数据库未找到":
                return response_failed("4000", str(api_url[0] + api_url[1]))

            api_headers = RegularMatch(test_case.api_headers, data['environment'])
            if api_headers[0] == "该变量数据库未找到":
                return response_failed("4000", str(api_headers[0] + api_headers[1]))

            json_header = api_headers.replace("\'", "\"")
            if test_case.api_headers == '':
                header = test_case.api_headers
            else:
                try:
                    header = json.loads(json_header)
                except json.decoder.JSONDecodeError:
                    return response_failed('30000', "header类型错误，用例名称: " + str(test_case.api_test_case_name))
            logger.info(json_header)

            api_parameter_body = RegularMatch(test_case.api_parameter_body, data['environment'])
            if api_parameter_body[0] == "该变量数据库未找到":
                return response_failed('40000', "该变量数据库未找到，用例名称: " + str(test_case.api_test_case_name) + "\n" + "变量值：" +
                                       str(api_parameter_body[0] + api_parameter_body[1]))

            json_par = api_parameter_body.replace("\'", "\"")
            if api_parameter_body == '':
                payload = api_parameter_body
                logger.info(payload)
            else:
                try:
                    payload = json.loads(json_par)
                    logger.info(payload)
                except json.decoder.JSONDecodeError:
                    return response_failed('30000', "参数类型错误，用例名称: " + str(test_case.api_test_case_name))

            # Params参数
            parameter_data = ApiParameterData.objects.filter(api_test_case_id=case['api_test_case_id'])
            api_parameter_dict = {}
            for api_parameters in parameter_data:
                if api_parameters.api_must_parameter == "true":
                    api_parameter_dict.update(
                        {api_parameters.api_parameter_name: api_parameters.api_parameter_value})
                else:
                    pass
            if api_parameter_dict == {}:
                api_parameter_data = {}
            else:
                api_parameter_data = RegularMatch(str(api_parameter_dict), data['environment'])

            if api_parameter_data == {}:
                data_payload = api_parameter_data
                logger.info(data_payload)
            else:
                try:
                    data_payload = ast.literal_eval(api_parameter_data)
                except json.decoder.JSONDecodeError:
                    return response_failed("30000", "Parameter参数类型错误" + api_parameter_data)
            r = InterfaceRequest(str(test_case.api_method), str(test_case.api_parameter_types),
                                 api_url, header, payload, data_payload)

            if r == "请求超时":
                return response_failed('30000', "接口请求超时:" + str(test_case.api_test_case_name))

            try:
                response_message = r.json()
            except json.decoder.JSONDecodeError:
                return response_failed('30000', "接口返回结果类型错误非JSON格式:" + str(test_case.api_test_case_name))

            # 断言
            if test_case.api_assert_type == '':
                result = "断言内容为空"
                logger.error(result)

            elif test_case.api_assert_type == 1:
                try:
                    r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
                                    r.text)

                    r_text_test = "".join(r_text.split())
                    r_text_data = "".join(test_case.api_assert_text.split())
                    assert r_text_data in r_text_test
                except Exception as e:
                    result = "断言失败: 响应内容中未包含 断言内容，断言内容： %s ，响应内容：%s" % (r_text_data, r_text_test)
                    logger.error(result + str(e))
                    return response_failed('30000', "断言失败，用例名称: " + str(test_case.api_test_case_name) + "\n" +
                                           "断言结果：" + result)
            elif test_case.api_assert_type == 2:
                try:
                    r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
                                    r.text)
                    r_text_test = "".join(r_text.split())
                    r_text_data = "".join(test_case.api_assert_text.split())
                    assert r_text_data == r_text_test
                except Exception as e:
                    result = "断言失败: 断言内容 %s 与响应结果不匹配，%s" % (r_text_data, r_text_test)
                    logger.error(result, e)
                    return response_failed('30000', "断言失败，用例名称: " + str(test_case.api_test_case_name) + "\n" +
                                           "断言结果：" + result)
            elif test_case.api_assert_type == 3:

                database = APIDatabase.objects.get(id=test_case.dataBase_id)
                db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
                              database.database)
                sql = data['database_sql']
                count = db.get_count(sql)
                db.close()
                if str(count) == str(test_case.api_assert_text):
                    result = '断言成功'
                    logger.error(result)
                else:
                    result = '断言失败,查询的数据是： %s' % str(count)
                    logger.error(result)
                    return response_failed('30000', "断言失败，用例名称: " + str(test_case.api_test_case_name) + "\n" +
                                           "断言结果：" + result)
            elif test_case.api_assert_type == 4:
                try:
                    assert test_case.api_assert_text == str(r.status_code)
                    result = "断言成功"
                except Exception as e:
                    result = "断言失败: code状态码 %s 与响应状态码不匹配，%s" % (test_case.api_assert_text, str(r.status_code))
                    logger.error(result, e)
                    return response_failed('30000', "断言失败，用例名称: " + str(test_case.api_test_case_name) + "\n" +
                                           "断言结果：" + result)

            parameter_extraction = ApiParameterExtraction.objects.filter(api_test_case_id=case['api_test_case_id'])
            if parameter_extraction == "" or None:
                pass
            else:
                # 提取变量
                try:
                    api_result = json.loads(r.text)
                except Exception as e:
                    logger.info('json转换失败（变量）：' + str(e))
                    pass
                for parameter_extractions in parameter_extraction:
                    v_text = parameter_extractions.api_value_variable.split(".")
                    try:
                        api_results = ExtractParameters(v_text, api_result)
                        api_parameter_extraction = ApiParameterExtraction.objects.get(
                            api_key_variable=str(parameter_extractions.api_key_variable))
                        api_parameter_extraction.api_variable_results = str(api_results)
                        api_parameter_extraction.save()
                    except Exception as e:
                        logger.info('参数提取失败' + str(e))
                        return response_failed('30000', "参数提取失败，用例名称:" +
                                               str(test_case.api_test_case_name) + '\n' + "异常信息：" + str(e))

        return response_success("调试成功")
