import psutil
import redis
from apps.monitor.models import AuditLog
from apps.system.models import User
from datetime import datetime
from apps.utils.tools import compare_values
from apps.utils.models import get_model_info
from server.celery import celery_control, celery_inspect
from django_redis import get_redis_connection


def delete_auditlog(model, instance_id):
    """
    删除其对应的审计记录
    """
    model_name = get_model_info(model)
    AuditLog.objects.filter(model_name=model_name,
                            instance_id=instance_id).delete()


def create_auditlog(action: str, instance,  val_new: dict, val_old: dict = None, change_time: datetime = None, change_user: User = None, change_reason: str = '', ignore_fields: list = None):
    """
    生成审计日志
    action: create/update/delete/其他action
    """
    app_label_model_name = get_model_info(instance)
    if val_old is None:
        val_old = {}
    if ignore_fields is None:
        ignore_fields = getattr(instance, 'audit_ignore_fields', [
                                'create_by', 'update_by', 'create_time', 'update_time', 'id'])
    difference = []
    has_changed = False

    if action == 'create':
        has_changed = True
        change_user_l = change_user if change_user else instance.create_by
        change_time_l = change_time if change_time else instance.create_time
    elif action == 'delete':
        has_changed = True
        change_user_l = change_user if change_user else instance.update_by
        change_time_l = change_time if change_time else instance.update_time
    else:
        if action == 'update':
            change_user_l = change_user if change_user else instance.update_by
            change_time_l = change_time if change_time else instance.update_time
        else:
            has_changed = True
            change_user_l = change_user
            change_time_l = change_time
        for k, v in val_new.items():
            if k not in ignore_fields:
                if k not in val_old:
                    difference.append(
                        {'field': k, 'action': 'create', 'val_old': None, 'val_new': v})
                elif not compare_values(val_new.get(k), val_old.get(k), ignore_order=True):
                    difference.append(
                        {'field': k, 'action': 'update', 'val_old': val_old[k], 'val_new': v})
        if action == 'update' and difference:
            has_changed = True
    if has_changed:
        AuditLog.objects.create(
            action=action,
            model_name=app_label_model_name,
            instance_id=instance.id,
            val_new=val_new,
            difference=difference,
            change_reason=change_reason,
            change_user=change_user_l,
            change_time=change_time_l
        )


class ServerService:
    @classmethod
    def get_memory_dict(cls):
        ret = {}
        memory = psutil.virtual_memory()
        ret['total'] = round(memory.total/1024/1024/1024, 2)
        ret['used'] = round(memory.used/1024/1024/1024, 2)
        ret['percent'] = memory.percent
        return ret

    @classmethod
    def get_cpu_dict(cls):
        ret = {}
        ret['lcount'] = psutil.cpu_count()
        ret['count'] = psutil.cpu_count(logical=False)
        ret['percent'] = psutil.cpu_percent(interval=1)
        return ret

    @classmethod
    def get_disk_dict(cls):
        ret = {}
        disk = psutil.disk_usage('/')
        ret['total'] = round(disk.total/1024/1024/1024, 2)
        ret['used'] = round(disk.used/1024/1024/1024, 2)
        ret['percent'] = disk.percent
        return ret

    @classmethod
    def get_full(cls):
        return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()}


class CeleryMonitor:
    @classmethod
    def get_info(cls):
        count_active_task = 0
        count_scheduled_task = 0
        count_registered_task = 0
        active_tasks = celery_inspect.active()
        if active_tasks:
            _, first_value = active_tasks.popitem()
            count_active_task = len(first_value)
        scheduled_tasks = celery_inspect.scheduled()
        if scheduled_tasks:
            _, first_value = scheduled_tasks.popitem()
            count_scheduled_task = len(first_value)
        registered_tasks = celery_inspect.registered()
        if registered_tasks:
            _, first_value = registered_tasks.popitem()
            count_registered_task = len(first_value)
        return {
            'count_active_task': count_active_task,
            'count_scheduled_task': count_scheduled_task,
            'count_registered_task': count_registered_task,
        }


class RedisMonitor:
    @classmethod
    def get_info(cls):
        conn = get_redis_connection()
        return conn.info()
