# encoding: utf-8
from __future__ import unicode_literals

import json
import logging
import os
import time
from datetime import datetime

import tornadis
import tornado.web
from tornado import gen

from intranet.webauth.lib.role_cache import get_cache_version, get_version_timestamp, is_version_nonempty
from intranet.webauth.lib.settings import (
    WEBAUTH_IDM_CACHE_FOLDER,
    WEBAUTH_IDM_CACHE_TTL_FOR_MONITORING, WEBAUTH_QLOUD_SYNC_MARK_FILE, WEBAUTH_QLOUD_SYNC_AGE,
)

logger = logging.getLogger(__name__)

IDM_SYSTEMS_FILE = os.path.join(WEBAUTH_IDM_CACHE_FOLDER, "webauth_idm_systems.json")


def _load_idm_systems():
    if not os.path.exists(WEBAUTH_IDM_CACHE_FOLDER):
        logger.error('IDM cache folder not exists')
        return

    if not os.path.exists(IDM_SYSTEMS_FILE):
        logger.error('Cache file for Webauth IDM systems does not exists')
        return

    if os.path.getsize(IDM_SYSTEMS_FILE) == 0:
        logger.error('Cache file for Webauth IDM systems is empty')
        return

    with open(IDM_SYSTEMS_FILE) as f:
        return json.load(f)


@gen.coroutine
def check_cache_integrity():
    error = False

    idm_systems = _load_idm_systems()
    if idm_systems is None:
        error = True
    else:
        for system in idm_systems:
            if not system:
                continue
            output_path = os.path.join(WEBAUTH_IDM_CACHE_FOLDER, "%s.json" % system)
            if not os.path.exists(output_path):
                logger.error('Cache file for %s not exists' % system)
                error = True
                continue

            if os.path.getsize(output_path) == 0:
                logger.error('Cache file for %s is empty' % system)
                error = True

    raise gen.Return([["cache_integrity_max", float(not error)]])


@gen.coroutine
def check_cache_freshness():
    error = False

    idm_systems = _load_idm_systems()
    if idm_systems is None:
        error = True
    else:
        for system in idm_systems:
            if not system:
                continue

            output_path = os.path.join(WEBAUTH_IDM_CACHE_FOLDER, "%s.json" % system)
            if not os.path.exists(output_path):
                logger.error('Cache file for %s not exists' % system)
                error = True
                continue

            if time.time() - os.path.getmtime(output_path) > WEBAUTH_IDM_CACHE_TTL_FOR_MONITORING:
                logger.error('Cache file for %s expired' % system)
                error = True

        try:
            current_version = yield get_cache_version()
            if current_version is None:
                logger.error('There is no roles in Redis')
                error = True
            else:
                version_timestamp = yield get_version_timestamp(current_version)
                if version_timestamp is None:
                    logger.error('No timestamp set for current version')
                    error = True
                elif time.time() - version_timestamp > WEBAUTH_IDM_CACHE_TTL_FOR_MONITORING:
                    logger.error('Redis cache expired')
                    error = True
        except tornadis.TornadisException as err:
            logger.error('Could not connect to redis: {}'.format(err))

    raise gen.Return([["cache_freshness_max", float(not error)]])


@gen.coroutine
def check_redis_integrity():
    error = False

    try:
        version = yield get_cache_version()
        if version is None:
            logger.error('There is no roles in Redis')
            error = True
        else:
            is_nonempty = yield is_version_nonempty(version)
            if not is_nonempty:
                logger.error('Current cache version is empty')
                error = True
    except tornadis.TornadisException as err:
        logger.error('Could not connect to redis: {}'.format(err))
        error = True

    raise gen.Return([['redis_integrity_max', float(not error)]])


@gen.coroutine
def check_qloud_sync():
    error = False
    if os.getenv('CRON_COMPONENT') == '1':
        if not os.path.exists(WEBAUTH_QLOUD_SYNC_MARK_FILE):
            logger.error('Qloud sync file does not exist')
            error = True
        else:
            sync_age = time.time() - os.path.getmtime(WEBAUTH_QLOUD_SYNC_MARK_FILE)
            if sync_age > WEBAUTH_QLOUD_SYNC_AGE:
                hours = round(sync_age / 3600, 1)
                logger.error('Sync with qloud succeeded {} hours ago'.format(hours))
                error = True

    raise gen.Return([['check_qloud_sync_max', float(not error)]])


@gen.coroutine
def generate_cache_time():
    previous_sync_file_name = os.path.join(WEBAUTH_IDM_CACHE_FOLDER, 'previous_sync.json')
    last_sync_file_name = os.path.join(WEBAUTH_IDM_CACHE_FOLDER, 'last_sync.json')
    try:
        with open(previous_sync_file_name) as input_file:
            prev_sync_stat = {
                key: datetime.strptime(value, '%Y-%m-%d %H:%M:%S.%f')
                for key, value in json.load(input_file).items()
            }
    except Exception:
        logger.exception('Failed to read data on previous synchronization')
        raise gen.Return([])
    try:
        with open(last_sync_file_name) as input_file:
            last_sync_stat = {
                key: datetime.strptime(value, '%Y-%m-%d %H:%M:%S.%f')
                for key, value in json.load(input_file).items()
            }
    except Exception:
        logger.exception('Failed to read data on last synchronization')
        raise gen.Return([])
    last_two_caches_delta = (last_sync_stat['end'] - prev_sync_stat['begin']).total_seconds()
    last_cache_delta = (last_sync_stat['end'] - last_sync_stat['begin']).total_seconds()
    # ahhh - брать абсолютные значения; по группе, метагруппе и времени сохранять гистограмму значений
    raise gen.Return([
        ["time_of_last_two_cache_generations_ahhh", last_two_caches_delta / 60.0],
        ["time_of_cache_generation_ahhh", last_cache_delta / 60.0],
    ])


class Unistat(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        metrics_functions = [
            generate_cache_time,
            check_cache_integrity,
            check_cache_freshness,
            check_redis_integrity,
            check_qloud_sync,
        ]
        all_metrics = []

        for func in metrics_functions:
            metrics = yield func()
            all_metrics.extend(metrics)

        self.finish(json.dumps(all_metrics))
