#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File    : main_server.py
# @Time    : 2023/5/15 15:39
# @Author  : bruxelles_li
# @Software: PyCharm
import logging
import requests
import threading
import sys
import json
from pathlib import Path
sys.path.append('../')
# 关闭多余连接
s = requests.session()
s.keep_alive = False
from detector_source import sys_info, cpu_info, mem_info
# 文件上传服务器定义
from fdfs_client.client import *
tracker_conf = get_tracker_conf("data/fdfs_client.conf")
client = Fdfs_client(tracker_conf)

formatter = logging.Formatter("%(asctime)s [%(levelname)s] <%(processName)s> (%(threadName)s) %(message)s")
# 创建一个logger, 并设置日志级别
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# 创建一个handler，用于将日志输出到控制台，并设置日志级别
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(formatter)
# 创建一个filehandler，用于将错误日志输出到文件，并设置日志级别
_tmp_path = os.path.dirname(os.path.abspath(__file__))
_tmp_path = os.path.join(_tmp_path, 'log')
Path(_tmp_path).mkdir(parents=True, exist_ok=True)
fh = logging.FileHandler(os.path.join(_tmp_path, "main_server_error.log"))
fh1 = logging.FileHandler(os.path.join(_tmp_path, "main_server_info.log"))
fh.setLevel(level=logging.ERROR)
fh1.setLevel(level=logging.INFO)
fh.setFormatter(formatter)
fh1.setFormatter(formatter)
# 同时将日志输出到控制台和文件
logger.addHandler(ch)
logger.addHandler(fh)
logger.addHandler(fh1)

# TODO: 定义进程存放列表
all_thread = []

"""
测试地址：http://114.115.185.13:9988/datapull/aiReport/report/callbackStatus
正式地址：http://192.168.1.70:9988/datapull/aiReport/report/callbackStatus
"""
# callback_url = "http://114.115.185.13:9988/datapull/aiReport/report/callbackStatus"
callback_url = "http://192.168.1.70:9988/datapull/aiReport/report/callbackStatus"


# todo: 合并段落和句子去重处理
def main_process(half_document_path, tables_dict, template_path, data_object, report_id,
                 output_report_path, report_name, template_id):
    # 输入半成品、模板和必要数据，对模板进行更新，输出更新后的模板路径
    try:
        from generate.gen_user_report_auto_generated import new_main_process
        from docx import Document
        half_document = Document(half_document_path)
        template_document = Document(template_path)
        report_processed_path = new_main_process(half_document=half_document,
                                                 tables_dict=tables_dict,
                                                 template_document=template_document,
                                                 data_object=data_object,
                                                 report_id=report_id,
                                                 output_report_path=output_report_path)
        # todo: 增加去重表格中的圆圈【空格】
        report_processed = Document(report_processed_path)
        from extract_table import read_document, replace_document
        report_processed = read_document(report_processed, "\u00A0", "")
        # todo: 增加缺失值项替换为空
        report_processed = replace_document(report_processed)
        final_report_name = '{}_{}.docx'.format(str(datetime.datetime.now().strftime('%Y%m%d%H%M%S')), report_name)
        UPLOAD_FOLDER = r'data/'  # 上传路径
        Path(UPLOAD_FOLDER).mkdir(parents=True, exist_ok=True)
        send_path = os.path.join(UPLOAD_FOLDER, final_report_name)
        report_processed.save(send_path)
        ret_upload = client.upload_by_filename(send_path)
        logger.info(ret_upload["Remote file_id"])
        # b'group1/M00/00/0A/wKjIlGRjcHiAVnTuAAEo5wnGJLQ89.docx'
        str_ret_upload = str(ret_upload["Remote file_id"])
        filePath = str_ret_upload.strip('b').replace("'", "").strip()
        logger.info(filePath)

        dict_result = {
            "status": "0",  # 处理状态 （"0" 成功， "1" 失败）
            "result": "处理成功",
            "id": report_id,  # 报告id
            "templeteId": template_id,  # 报告模板
            "filePath": filePath

        }
        logger.info(dict_result)
        # todo: 调用java的状态更新接口返回异常的结果
        payload = json.dumps(dict_result)
        headers = {
            'Content-Type': 'application/json'
        }
        r1 = requests.post(url=callback_url,
                           headers=headers, data=payload)
        logger.info(r1.text)
    except Exception as e:
        dict_result = {
            "status": "1",  # 处理状态 （0 成功， 1 失败）
            "result": "生成失败！+ {}".format(str(e)),
            "id": report_id,  # 报告id
            "templeteId": template_id,  # 报告模板
            "filePath": ""
        }
        # todo: 调用java的状态更新接口返回异常的结果
        payload = json.dumps(dict_result)
        headers = {
            'Content-Type': 'application/json'
        }
        r1 = requests.post(url=callback_url,
                           headers=headers, data=payload)
        logger.info(r1.text)
    return dict_result


def env_eval():
    # todo 获取资源相关信息(磁盘占用率、系统占用信息【超过3个为高】、CPU占用率、物理内存占用率)
    # disk_usage = disk_info()
    sys_usage = sys_info()
    cpu_usage = cpu_info()
    men_usage = mem_info()
    # todo 资源不够用时，返回 False
    if sys_usage > 20 or cpu_usage > str(95) or men_usage > str(95):
        return False
    # todo 资源够用时，返回 True
    return True


def system_start():
    while True:
        headers = {
            'Content-Type': 'application/json'
        }
        r1 = requests.post(url='http://localhost:4000/queue_size', headers=headers)
        r1_json = json.loads(r1.text)
        queue_left_number = r1_json['queue_left_number']
        logger.info("当前队列任务总数：" + str(queue_left_number))
        if queue_left_number == 0:
            time.sleep(6)
        else:
            # todo: 若任务队列不为空进行报告处理
            for i in range(queue_left_number):
                r2 = requests.post(url='http://localhost:4000/subject_consumer', headers=headers)
                r2_json = json.loads(r2.text)
                config_info = r2_json['data']
                logger.info(config_info)
                report_id = config_info["report_id"]
                template_id = config_info["template_id"]
                half_document_path = config_info["half_document_path"]
                tables_dict = config_info["tables_dict"]
                template_path = config_info["template_path"]
                data_object = config_info["data_object"]
                output_report_path = config_info["output_report_path"]
                report_name = config_info["report_name"]
                logger.info('##########报告生成服务###############')
                t = threading.Thread(target=main_process, args=(half_document_path, tables_dict, template_path,
                                                                data_object, report_id, output_report_path,
                                                                report_name, template_id),
                                     daemon=True)
                while True:
                    if env_eval():
                        break
                    else:
                        time.sleep(6)
                # 启动
                t.start()
                all_thread.append(t)


def system_resume():
    """
    恢复模型训练服务状态
    :return:
    """

    headers = {
        'Content-Type': 'application/json'
    }
    # 清空当前服务中的队列，避免重复启动服务
    r1 = requests.post(url='http://localhost:4000/queue_size', headers=headers)
    r1_json = r1.json()
    logger.info('当前队列数量：%d' % r1_json['queue_left_number'])
    if r1_json['queue_left_number'] > 0:
        logger.info('正在消费队列，直到队列为空！')
        while True:
            r2 = requests.post(url='http://localhost:4000/subject_consumer', headers=headers)
            r2_json = r2.json()
            if r2_json['queue_left_number'] == 0:
                logger.info('队列消费完毕！可放心进行数据去重入库服务 ...')
                break
    else:
        logger.info('队列为空！可放心进行数据去重入库服务 ...')


def start_up_check():
    """
    启动前检查
    :return:
    """
    while True:
        try:
            headers = {
                'Content-Type': 'application/json'
            }
            r0 = requests.post(url='http://localhost:4000/queue_size', headers=headers)
            # todo: 如果服务启动，即接口访问正常，则返回“真”
            server_started = True
        except requests.exceptions.ConnectionError as e:
            server_started = False
            logger.error("Error: ConnectionError" + str(e))
            logger.warning('服务未启动，请先启动server! 程序已退出。')
            exit(123)
            # logger.info('server正在尝试自启 ...')
            # time.sleep(3)
        if server_started:
            logger.info("server启动成功！报告生成服务已启动...")
            break


if __name__ == '__main__':
    # 开始启动后台处理服务
    start_up_check()
    logger.info('报告生成服务恢复中 ...')
    system_resume()
    time.sleep(30)
    logger.info('报告生成服务恢复完成！')
    logger.info('报告生成服务运行中 ...')
    system_start()

