import gzip
import collections
from flask import make_response, json, current_app
import numpy as np
import pandas as pd
from app.errors import *
import gc
from app import db
from app.models import Validation
import yaml
import requests
from app.main.utils.db_util import return_rg


def response_message(data=None, status=200):
    if status != 200:
        try:
            error = {'fa': data.message_fa, 'en': data.message_en}
        except AttributeError:
            print(data)
            error = MethodError()
            error = {'message_fa': error.message_fa, 'message_en': error.message_en}
        resp_dict = {'message': error}
    else:
        resp_dict = data
    resp_dict = json.loads(json.dumps(resp_dict, default=convert, sort_keys=False).replace('"None"', 'null')
                           .replace('NaN', 'null'), strict=False)
    content = gzip.compress(json.dumps(resp_dict, ensure_ascii=False, indent=3, default=convert,
                                       sort_keys=False).encode('utf8'), 5)
    response = make_response(content, status)
    response.headers['Content-length'] = len(content)
    response.headers['Content-Encoding'] = 'gzip'
    response.headers['Content-Type'] = 'application/json; charset=utf-8'
    response.headers.add('Access-Control-Allow-Origin', '*')
    gc.collect()
    return response


def deep_dict_update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = deep_dict_update(d.get(k, {}), v)
        else:
            d[k] = v
    return d


def convert(o):
    if isinstance(o, np.int64):
        return int(o)
    if isinstance(o, np.bool_):
        if o:
            return True
        else:
            return False
    if pd.isna(o):
        return None
    if o is np.ma.masked:
        return None
    json.dumps(o)


def read_data(puid=None, ruleset=None, cols=[], path=None):
    if puid:
        if ruleset:
            ruleset.data['type'] = 'rp'
            uid = ruleset.data['uid']
        else:
            uid = puid
        if cols:
            req = requests.post(f'{current_app.config["IO"]}/get_data/{uid}', json={'columns': cols, 'where': 'rules'})
        else:
            req = requests.post(f'{current_app.config["IO"]}/get_data/{uid}', json={'form_code': 'all', 'where': 'rules'})
        return pd.DataFrame(req.json()['data'])
    else:
        if not path:
            path = 'app/main/static/sample_data.xlsx'
        return pd.read_excel(path)


def read_rules(rsid=None, rgid=None, where='file', path=None):
    if where == 'db':
        if rgid:
            return return_rg(rsid, rgid)
    else:
        if not path:
            path = 'app/main/static/rule_config.yml'
        return yaml.load(open(path), Loader=yaml.FullLoader), None


def write_validations(data, where='file', path=None):
    if where == 'db':
        try:
            # data = data.loc[~data['validation']]
            obj = []
            data.apply(lambda x: obj.append(Validation(rid=x['rid'], rgid=x['rgid'], modified_date=x['modified_date'],
                                            responsible=x['responsible'], created_date=x['created_date'])), axis=1)
            db.session.bulk_save_objects(obj)
            db.session.commit()
        except Exception as e:
            return str(e)
    else:
        try:
            if not path:
                path = 'validation.xlsx'
            data.to_excel(path)
        except Exception as e:
            return str(e)
    return 'success'
