import os, uuid, json, requests

from lib import lockerjwt
from lib.commonlib import CommonLib
from lib.mongolib import Mongolib
from flask import Flask, request, g
from flask_cors import CORS
from werkzeug.serving import WSGIRequestHandler

from lib.validations import Validation
from lib import otp_service
from lib import family_services


otp_connector = otp_service.OTP_services()
family_connector = family_services.Family_services()


CommonLib = CommonLib()
MongoLib = Mongolib(os.getenv('MONGO_DB_ACCOUNTS'),
                    os.getenv('MONGO_URI_ACCOUNTS'))

allowed_origin = os.getenv('ALLOWED_ORIGIN')
MAX_CONTENT_LENGTH = os.getenv('MAX_CONTENT_LENGTH')
app = Flask(__name__)
cors = CORS(app, origins=allowed_origin)
app.config['JSON_SORT_KEYS'] = False



@app.before_request
def before_request():
    try:
        if request.method == 'OPTIONS':
            return {"status": "error", "error_description": "OPTIONS OK"},200
        
        bypass_urls=('jwt_login','healthcheck')
        if request.path.split('/')[1] in bypass_urls:
            return
        jwtlib = lockerjwt.LockerJwt(request)
        status_code, jwtres = jwtlib.jwt_login()
        # print(jwtres)
        if status_code == 200:
            g.digilockerid = jwtres['digilockerid']
            g.device_security_id = jwtres['device_security_id']
            g.token = jwtres['token']
        else:
            return jwtres, status_code
    except Exception as e:
        return {"status": "error", "error_description": "Exception(JWT):" + str(e)},401


@app.route('/family/register', methods=['POST'])
def family_register():
    try:
        aadhaar = CommonLib.filter_input(field=request.values.get('aadhaar'))
        name = CommonLib.filter_input(field=request.values.get('name'))
        dob = CommonLib.filter_input(field=request.values.get('dob'))
        gender = CommonLib.filter_input(field=request.values.get('gender'))
        relation = CommonLib.filter_input(field=request.values.get('relation'))
        mobile = CommonLib.filter_input(field=request.values.get('mobile'))
        txn = str(uuid.uuid4())
        
        form_validation = family_connector.form_validation(aadhaar, name, dob, gender, relation, mobile)
        
        if form_validation['status'] == 'error':
            return form_validation
        
        # CHECK FOR txn whether exists in users digilockerid
        res = family_connector.check_unique_uuid(txn)
        if res:
            txn = res
        else:
            # we can generate txn again...ask to sir?
            # return {"status": "error", "error_description": 'User alreday exists with given txnId'}
            txn = str(uuid.uuid4())

        #encrypting aadhaar
        secret = bytes(os.getenv('JWT_SECRET'), 'utf-8')
        jwtlib = lockerjwt.LockerJwt(request)
        aadhaarHash = jwtlib.aes_encryption(aadhaar,secret)
        # aadhaar_dec = jwtlib.aes_decryption(aadhaarHash,secret)
        
        #preparing data
        data = {
            'aadhaar':aadhaarHash,
            'name':name,
            'dob':dob,
            'gender':gender,
            'relation':relation,
            'mobile':mobile,
            'txn':txn
        }
        digilockerid = g.digilockerid
        #storing data in redis and mongodb
        return family_connector.store_family_data(digilockerid, data)

    except Exception as e:
        print(str(e))
        return {"status": "error", "error_description": str(e)}


@app.route('/family/verify_pin', methods=['POST'])
def verify_pin():
    try:
        pin = CommonLib.filter_input(field=request.values.get('pin'))
        txn = CommonLib.filter_input(field=request.values.get('txn'))
        digilockerid = g.digilockerid
        
        #txn is valid or not check from redis  
        redis_result = family_connector.get_redis_data(digilockerid+'_'+txn+'_family_details')
        
        if redis_result is None:
            return {"status": "error", "error_description": 'Session Expired.'}
        
        redis_data = json.loads(redis_result)
        
        # pin verification function
        valid_pin = Validation.pin_validation(pin)
        if valid_pin[1]['status']=='error':
            return {'status': 'error', 'error_description': valid_pin[1]['error_description']}

        data = family_connector.verify_pin(digilockerid, pin)
        if data['status'] == 'success':
            
            registered_mobile = data['mobile']
            family_mobile = redis_data['mobile']
            if registered_mobile == family_mobile:
                #do demographic auth
                secret = bytes(os.getenv('JWT_SECRET'), 'utf-8')
                jwtlib = lockerjwt.LockerJwt(request)
                aadhaar_dec = jwtlib.aes_decryption(redis_data['aadhaar'],secret)
                redis_data['aadhaar']=aadhaar_dec
                demoauth_res = family_connector.demoAuth(redis_data, digilockerid)
                demoauth_res['next_flow'] = 'NA' 
                return demoauth_res
            else:
                #send otp on family mobile given
                send_otp_status= otp_connector.send_mobile_otp(family_mobile)
                if send_otp_status['status'] == 'error':
                    return send_otp_status
                send_otp_status['next_flow'] = 'verify_otp'
                return send_otp_status
        
        else:
            return {"status": "error", "error_description": 'error'}
    except Exception as e:
        print(str(e))
        return {"status": "error", "error_description": str(e)}

@app.route('/family/send_mobile_otp', methods=['POST'])
def send_mobile_otp():
    try:
        txn = CommonLib.filter_input(field=request.values.get('txn'))

        digilockerid = g.digilockerid
        redis_result = family_connector.get_redis_data(digilockerid+'_'+txn+'_family_details')
        if redis_result is None:
            return {"status": "error", "error_description": 'Session Expired.'}
        
        redis_data = json.loads(redis_result)
        
        res = otp_connector.send_mobile_otp(redis_data['mobile'])
        return res
        
    except Exception as e:
        print(str(e))
        return {"status": "error", "error_description": str(e)}


@app.route('/family/verify_mobile_otp', methods=['POST'])
def verify_mobile_otp():
    try:
        txn = CommonLib.filter_input(field=request.values.get('txn'))
        otp = CommonLib.filter_input(field=request.values.get('otp'))
        valid_otp = Validation.otp_validation(otp)

        
        if valid_otp[1]['status'] == 'error':
            return {"status": "error", "error_description": valid_otp[1]['error_description']}
        digilockerid = g.digilockerid
        redis_result = family_connector.get_redis_data(digilockerid+'_'+txn+'_family_details')
        if redis_result is None:
            return {"status": "error", "error_description": 'Session Expired.'}
        
        redis_data = json.loads(redis_result)

        res = otp_connector.verify_mobile_otp(redis_data['mobile'], otp)
        if res['status']=='error':
            return res
        
        secret = bytes(os.getenv('JWT_SECRET'), 'utf-8')
        jwtlib = lockerjwt.LockerJwt(request)
        aadhaar_dec = jwtlib.aes_decryption(redis_data['aadhaar'],secret)
        redis_data['aadhaar'] = aadhaar_dec

        #create account once otp verifies successfully    
        return family_connector.demoAuth(redis_data, digilockerid)
        
    except Exception as e:
        print(str(e))
        return {"status": "error", "error_description": str(e)}

# getting the family list from parent digilocker id
@app.route('/family/family_list', methods=['GET'])
def family_list():
    try:
        # getting the digilocker id from jw token
        digilockerid = CommonLib.filter_input(field=g.digilockerid)

        # filter where all the created_by field will be shown which is matching with the digilocker_id
        where = {"created_by": digilockerid}
        data = MongoLib.find('users_profile', where, projection={'_id': 0,'user_from': 0,'account_type':0,'converted_by': 0,'created_on': 0,'_v': 0})
        res = []
        for x in data:
            if x['digilockerid'] != x['created_by']:
                res.append(x)
                print(res)

        return {"status": "success", "data":res}
    except Exception as e:
        return {"status": "error", "error_description": str(e)}


@app.route('/family/issued_doc', methods=['POST'])
def issued_doc():
    try:
        url = 'https://idss.digitallocker.gov.in/index.php/apps/issued_docs/api/1.0/issueddocs'
        
        # getting the digilocker id from jw token
        digilockerid = CommonLib.filter_input(field=g.digilockerid)
        # filter where all the created_by field will be shown which is matching with the digilocker_id
        where = {"created_by": digilockerid}
        data = MongoLib.find('users_profile', where, projection={'_id': 0,'user_from': 0,'created_by': 0,'account_type':0,'converted_by': 0,'created_on': 0,'_v': 0})
        res = []
        jwtlib = lockerjwt.LockerJwt(request)
        for x in data:
            x['jwt'] = jwtlib.jwt_generate(x['digilockerid'])
            headers = {'jtoken': x['jwt'],'device-security-id':g.device_security_id}
            response = requests.request("POST", url, headers=headers)
            issued_docs = json.loads(response.text)
            # print(issued_docs)
            res[x['digilockerid']] = issued_docs
            
        return {"status": "success", "data": res}

    except Exception as e:
        return {"status": "error", "error_description": str(e)}


@app.route('/family/relationship', methods=['GET'])
def relationship():
    relations = {'status': 'success',
                 'data': [{'name': 'Partner'}, {'name': 'Son'}, {'name': 'Daughter'}, {'name': 'Mother'},
                          {'name': 'Father'}, {'name': 'Sister'}, {
                              'name': 'Brother'}, {'name': 'Mother-in-law'},
                          {'name': 'Sister-in-law'}, {'name': 'Uncle'}, {
                              'name': 'Aunt'}, {'name': 'Cousin'},
                          {'name': 'Grand Father'}, {'name': 'Grand Mother'}, {'name': 'Others'}]}
    return relations



@app.route('/healthcheck', methods=['GET', 'POST'])
def healthcheck():
    return {"status": "success"}


debug_mode = True
if os.getenv('DEBUG_MODE') == 'False':
    debug_mode = True
WSGIRequestHandler.protocol_version = "HTTP/1.1"
app.run('0.0.0.0', '8000', debug=True)
