from __future__ import unicode_literals
import json
import re

from flask import request
from flask import make_response, jsonify
from redis.exceptions import RedisError
from library.python.vault_client.errors import ClientError
from load.projects.tank_finder.lib.app import app, Error400, Error404
from load.projects.tank_finder.lib.config import logger
from load.projects.tank_finder.lib.tools import get_rt_networks, get_host_dc, get_deploy_hosts, get_deploy_tanks, get_conductor_tanks, get_rtc_tanks, get_rtc_targets, get_from_cache


headers = {'Content-Type': 'application/json'}


@app.errorhandler(Error404)
def catch_404(error):
    logger.error(error.message)
    return make_response(json.dumps({'result': 'error', 'error_msg': error.message}), 404, headers)


@app.errorhandler(Error400)
def catch_400(error):
    logger.error(error.message)
    return make_response(json.dumps({'result': 'error', 'error_msg': error.message}), 400, headers)


@app.route('/ping')
def ping():
    return 'Ping!'


@app.route('/check_hosts', methods=['GET'])
def check_hosts():
    hosts = []
    dc = []
    tank = request.args.get('tank')
    target = request.args.get('target')
    if not tank or not target:
        raise Error404('There are no tank or target parameters')

    hosts.append(tank)
    hosts.append(target)

    networks = get_rt_networks()

    for host in hosts:
        dc.append(get_host_dc(host, networks))

    return jsonify(result=all(c == dc[0] for c in dc)), 200, headers


@app.route('/tanks/list.json')
def tanks():
    target = request.args.get('target')
    service = request.args.get('service')
    group = request.args.get('group')

    c_tanks = []
    status = []
    target_port = None
    rt_networks = get_rt_networks()

    if target:
        target_service = re.split(':', target, maxsplit=1)
        if target_service[0] == 'nanny':
            target, target_port = get_rtc_targets(app, target_service[1])[0].split(':')

        elif target_service[0] == 'deploy':
            try:
                target, target_port = get_deploy_hosts(*target_service[1].split('.'))[0], (target.split(':') + [80])[2]
            except (TypeError, IndexError):
                logger.error('Failed to get address for the stage %s', target_service[1], exc_info=True)
                target = None
        dc = get_host_dc(target, rt_networks).lower()

        if service:
            service_parts = service.split(':')
            if service_parts[0] == 'nanny':
                if group:
                    c_tanks = get_rtc_tanks(app, nanny_service=service_parts[1], group=group, data_center=dc, target=target, target_port=target_port)
                else:
                    c_tanks = get_rtc_tanks(app, nanny_service=service_parts[1], data_center=dc, target=target, target_port=target_port)
            elif service_parts[0] == 'deploy':
                try:
                    tanks = get_deploy_hosts(*(service_parts[1] + '..').split('.')[:3])
                    deploy_tanks = [tank for tank in tanks if get_host_dc(tank, rt_networks).lower() == dc]

                    if deploy_tanks:
                        c_tanks = get_deploy_tanks(tanks=deploy_tanks, tank_port=(service.split(':') + [8083])[2], data_center=dc, target=target,  target_port=target_port)
                    else:
                        raise Error404('Tank and target in the different datacentres. Crossd DC shooting is deprecated!')

                except Exception:
                    logger.error('Error during geting tanks from deploy', exc_info=True)
            else:
                raise Error404('Wrong service name/ Use nanny:{nanny_service_name} or deploy:')
        else:
            c_tanks = get_conductor_tanks(app, data_center=dc, target=target)

        if c_tanks:
            return json.dumps(c_tanks), 200, headers
        else:
            raise Error404('Can\'t find Hardware tanks for target: {}. \
                    Please try RTC tanks, if your target in Nanny/Deploy/Yp: https://nda.ya.ru/t/sN6_6Fng3ojJnf'.format(target))
    else:
        try:
            tanks_common = get_from_cache('tanks_common')
            if tanks_common:
                for tank in tanks_common:
                    status.append(get_from_cache('status_{}'.format(tank['tank'])))
                resp = {"no_more": False, "tanks": status}
                return json.dumps(resp), 200, headers
            else:
                raise Error404('Empty public tanks status')
        except (ClientError, RedisError) as e:
            logger.error('Cache error: %s', e)
            raise Error404('Can\'t read status from cache')


@app.route('/deploy')
def deploy():
    stage = request.args.get('stage')
    du = request.args.get('unit')
    dc = request.args.get('dc')

    if stage:
        return json.dumps({"fqdn": get_deploy_hosts(stage, du, dc)}), 200, headers
    else:
        raise Error404('Stage is not set.')


@app.route('/nanny')
def nanny():
    service = request.args.get('service')
    group = request.args.get('group') or ''
    dc = request.args.get('dc') or ''

    if service:
        return json.dumps({"fqdn": get_rtc_targets(app, nanny_service=service, nanny_group=group, data_center=dc)}), 200, headers
    else:
        raise Error404('Service is not set')


@app.route('/target_dc')
def get_target_dc():
    target = request.args.get('target')
    if target:
        target_service = re.split(':', target, maxsplit=1)
        if target_service[0] == 'nanny':
            target, _ = get_deploy_hosts(app, target_service[1])
        if target_service[0] == 'deploy':
            stage, du, dc = (target_service[1].split('.') + ['', ''])[:3]
            target = get_deploy_hosts(stage, du, dc)[0]
        dc = get_host_dc(target, get_rt_networks()).upper()
        return json.dumps({"datacenter": dc}), 200, headers
    else:
        raise Error404('Target is not set!')
