import gzip
import json
import os
import select
from collections import Counter
from datetime import datetime
from pprint import pprint

import jsonpath
import paramiko
from mitmproxy import ctx

from garbevents.settings import Settings as ST


class GetData:
    """
    Capture of buried points in the background.
    A engine HTTP request class.
    """

    events_list = []
    now_time = datetime.now()
    new_time = now_time.strftime("%Y-%m-%d %H:%M:%S")

    @staticmethod
    def chunks(arr, n):
        """

        :param arr:
        :param n:
        :return:
        """
        return [arr[i : i + n] for i in range(0, len(arr), n)]

    @staticmethod
    def gzip_decompress(data):
        """
        解密上报数据
        :param data:
        :return:
        """
        try:
            return gzip.decompress(data)
        except AttributeError:
            from io import StringIO

            buf = StringIO()
            buf.write(data)
            fd = gzip.GzipFile(fileobj=buf, mode="r")
            fd.rewind()
            value = fd.read()
            fd.close()
            return value

    @staticmethod
    def backstage(serverip, user, pwd):
        """

        :param serverip:
        :param user:
        :param pwd:
        :return:
        """
        events_list = []
        # 构造当天的日志文件名字，根据不同的埋点名称再做修改
        now_time = datetime.now()
        new_time = now_time.strftime("%Y-%m-%d")
        log = "sensors.log." + new_time

        # 进行连接
        ctx.log.info("------------开始连接服务器(%s)-----------" % serverip)
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ctx.log.info("------------开始认证......-----------")
        client.connect(serverip, 22, username=user, password=pwd, timeout=4)
        ctx.log.info("------------认证成功!.....-----------")
        # 开启channel 管道
        transport = client.get_transport()
        channel = transport.open_session()
        channel.get_pty()
        # 执行命令nohup.log.2017-12-30
        tail = "tail -n 0 -f  " + ST.url + log
        # 将命令传入管道中
        channel.exec_command(tail)
        while True:
            # 用于精确查出什么时间时候没有值
            news_time = now_time.strftime("%Y-%m-%d %H:%M:%S")

            # 判断退出的准备状态
            if channel.exit_status_ready():
                break
            try:
                # 通过socket进行读取日志，linux相当于客户端
                rl, wl, el = select.select([channel], [], [])
                if len(rl) > 0:
                    recv = channel.recv(1024)
                    # 此处将获取的数据解码成utf-8的读取
                    AAA = recv.decode("utf-8", "ignore")
                    BBB = AAA.split("\n")
                    DDD = BBB[0:2]
                    for CCC in DDD:
                        try:
                            GGG = str(CCC)
                            data = json.loads(GGG)
                            try:
                                event = data["event"]
                                if event in ST.all_events:
                                    ctx.log.info(f"【后端】获取到的埋点事件名称是 ====>{event}")
                                    events_list.append(event)
                                    count = Counter(events_list)
                                    lost_list = list(
                                        set(ST.all_events).difference(set(events_list))
                                    )

                                    # 用于遍历对应event事件里面的具体信息
                                    for event_value in ST.events_properties[event]:
                                        # 记录下坑，下面不能直接在里面传event_value不然取不到值
                                        result = jsonpath.jsonpath(
                                            data, f"$..{event_value}"
                                        )
                                        if result is False:
                                            ctx.log.info(
                                                f"【后端】请注意！！！请注意！！！{event}事件未获取到{event_value}值"
                                            )
                                            with open(
                                                f"{ST.report_path}/【后端】埋点事件参数没有值的统计.txt",
                                                "a+",
                                                encoding="utf-8",
                                            ) as file01:
                                                # 用于记录埋点事件参数没有值的统计.txt
                                                file01.write(
                                                    "【后端】{}请注意！！！请注意！！！{}事件未获取到{}值!!!".format(
                                                        news_time, event, event_value
                                                    )
                                                    + "\n"
                                                )
                                        else:
                                            ctx.log.info(
                                                f"【后端】获取到的埋点事件:{event}的自定义参数{event_value}的值是{result}："
                                            )

                                    # 在已上报的埋点事件统计.txt记录已经获取到的事件
                                    with open(
                                        f"{ST.report_path}/【后端】已上报的埋点事件统计.txt",
                                        "w",
                                        encoding="utf-8",
                                    ) as file03:
                                        # file03.writelines(events_list)
                                        for line in events_list:
                                            file03.write(line + "\n")

                                    # 在漏上报的埋点事件统计.txt记录已经获取到的事件
                                    with open(
                                        f"{ST.report_path}/【后端】漏上报的埋点事件统计.txt",
                                        "w",
                                        encoding="utf-8",
                                    ) as file04:
                                        # file04.writelines(lost_list)
                                        for lines in lost_list:
                                            file04.write(lines + "\n")
                                            ctx.log.info(
                                                f"【后端】暂未获取到这些埋点事件，可能存在漏上报事件 ====>{lines}"
                                            )

                                    ctx.log.info(f"【后端】累计的埋点事件统计次数{count}")
                                    with open(
                                        f"{ST.report_path}/【后端】累计的埋点事件统计次数.txt",
                                        "w",
                                        encoding="utf-8",
                                    ) as file02:
                                        # 用于记录埋点事件参数没有值的统计.txt
                                        file02.write(f"【后端】累计统计到的埋点次数{count}!!!" + "\n")

                                    # 不存在对应txt文件时，先创建txt文件
                                    if not os.path.exists(ST.report_path):
                                        os.mkdir(ST.report_path)
                                        ctx.log.info(
                                            ST.report_path + "Successfully created！"
                                        )
                                else:
                                    ctx.log.info(f"该事件{event}不在你录的事件中")
                            except Exception:
                                ctx.log.info("json中不存在event字段,请查看上面具体json查询想要的内容字段")
                                pprint(f"json中不存在event字段{data}")
                                break
                        except json.decoder.JSONDecodeError as e01:
                            pass
                        except Exception as e02:
                            print(e02)
                            ctx.log.info("读取不到日志文件，还未生成，请先手动触发事件生成日志")

            # 键盘终端异常
            except KeyboardInterrupt:
                print("Caught control-C")
                channel.send("\x03")  # 发送 ctrl+c
                channel.close()
        client.close()
