from django.http import HttpResponse
from django.http import HttpResponseServerError, HttpResponseBadRequest
from django.shortcuts import render_to_response
from django.utils.html import escape

from .cluster import get_cluster_data as cluster
from .people import is_saas_developer
from . import people
from . import helpers

from simplediff import diff

import json
import urllib


def storage(request):
    path = escape(request.GET.get('path', ''))
    if request.GET.get('format', '') != 'json':
        return render_to_response('storage.html', {'storage': {'path': path}})
    version = request.GET.get('version') or '-1'
    st_res = cluster.get_storage_value(path, version)
    if not st_res['success']:
        return HttpResponseServerError(json.dumps(st_res))
    is_file = 'data' in st_res['ans']
    fcontent = st_res['ans']['data'] if is_file else ''
    if is_file:
        base_path = ('/' + path.strip('/')).rsplit('/', 1)[0]
        tree_res = cluster.get_storage_value(base_path)
        if tree_res['success']:
            tree = tree_res['ans']
        else:
            tree = {}
    else:
        base_path = path
        tree = st_res['ans']
    parent_path = ('/' + base_path.strip('/')).rsplit('/', 1)[0]
    render_dict = {'storage': {
        'path': path,
        'base_path': base_path,
        'parent_path': parent_path,
        'is_file': is_file,
        'filecontent': fcontent,
        'tree': tree}}
    if request.GET.get('format', '') == 'json':
        return HttpResponse(json.dumps(render_dict))
    return render_to_response('storage.html', render_dict)


def storage_versions(request):
    path = request.GET.get('path', '')
    if not path:
        return HttpResponseBadRequest(json.dumps({'success': False, 'error': 'path is not specified'}))
    sp_parts = ('/' + path.strip('/')).rsplit('/', 1)
    base_path = sp_parts[0]
    file_name = sp_parts[1]
    if not file_name:
        return HttpResponseBadRequest(json.dumps({'success': False, 'error': 'path is not specified'}))
    dir_hist = cluster.get_history(base_path)
    if not dir_hist['success']:
        return HttpResponse(json.dumps(dir_hist))
    fns = [fn for fn in dir_hist['ans'].get('files', []) if len(fn) > 10 and fn[:-10] == file_name]
    versions = [fv[-10:] for fv in fns]
    if len(versions) > 10:
        versions = versions[-10:]
    versions = [v.lstrip('0') or '0' for v in versions]
    res = {'success': True, 'versions': versions}
    return HttpResponse(json.dumps(res))


def storage_modify(request):
    path = request.GET.get('path')
    if not path or len(path) < 3:
        return HttpResponseBadRequest(json.dumps({'error': 'path is not specified'}))
    action = request.GET.get('action')
    if not action:
        return HttpResponseBadRequest(json.dumps({'error': 'action is not specified'}))
    login = request.yauser.login if request.yauser.is_authenticated() else 'unauthorized'
    if not is_saas_developer(login):
        slas_res = helpers.get_all_slas()
        if not slas_res['success']:
            return HttpResponseBadRequest(json.dumps({'error': 'cannot get sla logins', 'result': slas_res}))
        slas = slas_res['result']
        usr_services = people.my_services(slas, login)
        has_rights = False
        for usv in usr_services:
            if ('configs/' + usv + '/') in path:
                has_rights = True
                break
        if not has_rights:
            return HttpResponseBadRequest(json.dumps({'error': 'login ' + login + ' cannot do this', 'warnings': slas_res.get('warnings')}))
        if path.strip().endswith('sla_description.conf'):
            return HttpResponseBadRequest(
                json.dumps({'error': 'users cannot modify sla_description, please write to saas-duty chat', 'warnings': slas_res.get('warnings')}))
    if action == 'set':
        hex = request.GET.get('hex')
        res = cluster.set_storage_value(path, request.body, login, hex)
        return HttpResponse(json.dumps(res))
    return HttpResponseBadRequest(json.dumps({'error': 'no such action ' + escape(action)}))


def storage_fetch_fml(request):
    login = request.yauser.login if request.yauser.is_authenticated() else 'unauthorized'
    fml_id = request.GET.get('fml_id')
    parent_path = request.GET.get('parent_path')
    file_name = request.GET.get('file_name')
    res = cluster.fetch_fml_formula(fml_id, file_name, parent_path, login)
    return HttpResponse(json.dumps(res))


def download(request):
    path = request.GET.get('path')
    if not path:
        return HttpResponseBadRequest(json.dumps({'error': 'path is not specified'}))
    try:
        dc = cluster.download_conf(path)
        response = HttpResponse(dc, content_type='application/octet-stream')
        #  response['Content-Disposition'] = 'attachment; filename="' + path.strip('/').split('/')[-1] + '"'
        return response
    except Exception as e:
        return HttpResponseBadRequest(json.dumps({'error': '%s' % e}))


def remove(request):
    path = request.GET.get('path')
    if not path or not path.strip('/'):
        return HttpResponseBadRequest(json.dumps({'error': 'path is not specified'}))
    is_file = request.GET.get('is_file')
    login = request.yauser.login if request.yauser.is_authenticated() else 'unauthorized'
    if not is_saas_developer(login, with_local=False):
        slas_res = helpers.get_all_slas()
        if not slas_res['success']:
            return HttpResponseBadRequest(json.dumps({'error': 'cannot get sla logins', 'result': slas_res}))
        slas = slas_res['result']
        usr_services = people.my_services(slas, login)
        has_rights = False
        path_removable = False
        for usv in usr_services:
            if ('configs/' + usv + '/') in path:
                has_rights = True
                if is_file == 'true':
                    path_removable = True
                    end_path = path[path.find('configs/' + usv + '/') + len('configs/' + usv + '/'):]
                    if '/' in end_path:
                        path_removable = False
                break
        if not has_rights:
            return HttpResponseBadRequest(
                json.dumps({'error': 'login ' + login + ' cannot do this', 'warnings': slas_res.get('warnings')}))
        if path.strip().endswith('sla_description.conf'):
            path_removable = False
        if not path_removable:
            return HttpResponseBadRequest(
                json.dumps({'error': 'path can be removed by saas dev only', 'warnings': slas_res.get('warnings')}))

    if len(path.strip('/').split('/')) < 2:
        return HttpResponseBadRequest(json.dumps({'error': 'cannot delete immediate children'}))
    res = cluster.remove_conf(path, login)
    return HttpResponse(json.dumps(res))


def config_diff_do(request):
    file_url_1 = request.GET.get('url1')
    file_version_2 = request.GET.get('version2', -1)

    our_file_url = urllib.parse.unquote(file_url_1)
    file_info_last = json.loads(our_file_url)
    if file_info_last['generator']['type'] == 'rty_diff':
        file_info_last['generator']['diff']['version'] = file_version_2
    else:
        file_info_last['generator']['version'] = file_version_2
    file_url_last = json.dumps(file_info_last).replace('\n', '').replace(' ', '')
    file_url_last_q = urllib.parse.quote(file_url_last)

    file_ver1_res = cluster.get_conf_by_url(file_url_1)
    file_ver2_res = cluster.get_conf_by_url(file_url_last_q)
    if not file_ver1_res['success']:
        return HttpResponseBadRequest(json.dumps(file_ver1_res))
    if not file_ver2_res['success']:
        return HttpResponseBadRequest(json.dumps(file_ver2_res))

    file_ver1_lines = file_ver1_res['ans'].split('\n')
    file_ver2_lines = file_ver2_res['ans'].split('\n')
    res = diff(file_ver1_lines, file_ver2_lines)
    html_res = ''
    stats = {'added': 0, 'deleted': 0, 'added_lines': 0, 'deleted_lines': 0}
    for r in res:
        tag_beg, tag_end = '', ''
        if r[0] == '+':
            stats['added'] += 1
            stats['added_lines'] += len(r[1])
            tag_beg, tag_end = '<ins>', '</ins>'
        elif r[0] == '-':
            stats['deleted'] += 1
            stats['deleted_lines'] += len(r[1])
            tag_beg, tag_end = '<del>', '</del>'
        html_res += '<br>' + tag_beg + r[0] + ('<br>' + r[0]).join(r[1]) + tag_end
    return HttpResponse(json.dumps({'success': True, 'diff': html_res, 'stats': stats}))


def parse_version(file_info):
    try:
        fn_url = urllib.parse.unquote(file_info['url'])
        fn_url_js = json.loads(fn_url)
        if 'version' in fn_url_js['generator']:
            return fn_url_js['generator']['version']
        else:
            if fn_url_js['generator']['type'] == 'rty_diff':
                return fn_url_js['generator']['diff']['version']
    except:
        return 0


def config_diff(request):
    service = request.GET.get('service')
    ctype = request.GET.get('ctype')
    slot = request.GET.get('slot', '')

    cur_res = cluster.list_conf(slot, service, ctype, False)
    if not cur_res['success']:
        return HttpResponseBadRequest(json.dumps(cur_res))

    last_res = cluster.list_conf(slot, service, ctype, True)
    if not last_res['success']:
        return HttpResponseBadRequest(json.dumps(last_res))

    filenames_1 = set([f['rename'] for f in cur_res['ans'].get('files', [])])
    filenames_2 = set([f['rename'] for f in last_res['ans'].get('files', [])])
    added_set = set([f for f in filenames_2 if f not in filenames_1])
    removed_set = set([f for f in filenames_1 if f not in filenames_2])
    different_set = {}
    added = []
    removed = []
    same = []
    different = []
    versions_1 = {}
    for f in cur_res['ans'].get('files', []):
        f['version'] = parse_version(f)
        if f['rename'] in removed_set:
            removed.append(f)
        else:
            versions_1[f['rename']] = f['version']
    for f in last_res['ans'].get('files', []):
        f['version'] = parse_version(f)
        if f['rename'] in added_set:
            added.append(f)
        else:
            if versions_1.get(f['rename'], -2) == f['version']:
                same.append(f)
            else:
                # f['old_version'] = versions_1[f['rename']]
                different_set[f['rename']] = f['version']
    for f in cur_res['ans'].get('files', []):
        if f['rename'] in different_set:
            f['last_version'] = different_set[f['rename']]
            different.append(f)

    render_dict = {'service': service, 'ctype': ctype,
                   'added': added, 'removed': removed,
                   'same': same, 'different': different}
    return render_to_response('diffs.html', render_dict)
