'''
Author: Abhijeet Anand
Email: abhijeet.anand@digitalindia.gov.in
Dated: 17/10/2021
Purpose: Functions family locker
Given by: Alok Ranjan sir
Task ID: 20111 
'''
import os

from dotenv import load_dotenv
from redis import client
from lib.redislib import RedisLib
from lib.mongolib import Mongolib
import json
import bcrypt
import requests
import time
import hashlib
from lib.validations import Validation
from lib import rabbitmqRegisterFamily
RabbitmqRegisterFamily = rabbitmqRegisterFamily.RabbitmqRegisterFamily()

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


load_dotenv()

'''Constants'''
ttl_family_data = os.getenv('REDIS_KEY_TTL_FAMILY_DATA')
mongo_collection_users = os.getenv('MONGO_COLLECTION_USERS')


class Family_services:
    def __init__(self):
        self.rs = RedisLib()

    def store_family_data(self, digilockerid, data):
        try:
            if data:                        
                #storing in redis
                redis_status = self.rs.set(key = digilockerid+'_'+data['txn']+'_family_details', value = json.dumps(data), ex=ttl_family_data)
                return {'status':'success','txn':data['txn'],'redis_status':redis_status}
            else:
                return {'status':'error'}

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

    def get_redis_data(self, key):
        try:
            if key:
                return self.rs.get(key = key)
            return {"status": "error", "error_description": "Some technical error occured."}
        except Exception as e:
            print(str(e))
            return {"status": "error", "error_description": str(e)}

    def verify_pin(self, digilockerid, pin):
        try:
            if pin and digilockerid:                        
                data = self.getUsersDataByDigilockerid(digilockerid)
                
                res = data['pin'].split('|')
                hash = res[1]
                validPin = self.match_pin(pin, hash)
                if validPin['status']=='success':
                    return {'status':'success','mobile':data['mobile_no']}
            return {'status':'error'}

        except Exception as e:
            print(str(e))
            return {'status':'error', 'error_description':str(e)}
    
    
    def match_pin(self, pin, hash):
        try:
            if pin != '' and hash:
                if self.password_verify(pin, hash):
                    return {"status": "success"}
                else:
                    return {"status": "error"}   
            else:
                return {"status": "error", "error_description":"Some Technical Error occured."}
        except Exception as e:
            print(str(e))
            return {"status": "error", "error_description": str(e)}

    def password_verify(self, password, hash):
        try:
            if len(hash) != 60 or len(password)!=6:
                return False
            else:
                compare = bcrypt.checkpw(password.encode("utf-8"), hash.encode("utf-8"))
                return (compare == True)
        except Exception as e:
            print(str(e))
            return False
    
    def getUsersDataByDigilockerid(self, digilockerid):
        try:
            if digilockerid:                        
                res = MongoLib.find(mongo_collection_users,{'digilockerid':digilockerid})
                for data in res:
                    if data:
                        return data
            else:
                return {'status':'error'}
        except Exception as e:
            print(str(e))
            return {"status": "error", "error_description": str(e)}

    def demoAuth(self, redis_data, parent_digilockerid):
        try:
            url = os.getenv('DEMO_AUTH_API_URL')
            clientid=os.getenv('DEMO_AUTH_API_CLIENTID')
            client_secret=os.getenv('DEMO_AUTH_API_CLIENT_SECRET')
            ts= int(time.time())
            fields = client_secret+clientid+str(ts)
            hmac = hashlib.sha256(fields.encode()).hexdigest()
            payload='uid='+redis_data['aadhaar']+'&name='+redis_data['name']+'&gender='+redis_data['gender']+'&dob='+redis_data['dob']+'&consent=Y'+'&hmac='+hmac+'&clientid='+clientid+'&ts='+str(ts)+'&mobile='+redis_data['mobile']
            
            headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
            }
            
            curl_response = requests.request("POST", url, headers=headers, data=payload)
            response = json.loads(curl_response.text)
            # response will have uid token, Check if Account Exists with that UID_Token
            if response['status'] =='error':
                return {"status": "error", "error_description":response['error_description']}
            
            uid_token = response['UID_Token']
            
            account_exists = self.checkForAccountExist(uid_token)
            if account_exists is not None:
                return {"status": "error", "error_description":"Account already exists"}
            else:
                # Create New Account through worker
                
                return self.createAccount(redis_data, uid_token, parent_digilockerid)
                    

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

    def createAccount(self, redis_data, uid_token, parent_digilockerid):
        try:
            userCreationData = {}
            userCreationData['user_id'] = redis_data['txn']
            userCreationData['digilockerid'] = redis_data['txn']
            userCreationData['user_from'] = ''
            userCreationData['data_directory_type'] = os.getenv('DEFAULT_DATADIRECTORY')
            userCreationData['user_type'] = os.getenv('DEFAULT_USERTYPE')
            userCreationData['uid'] = hashlib.md5(redis_data['aadhaar'].encode('utf-8')).hexdigest()
            userCreationData['date_of_birth'] = '-'.join((redis_data['dob'][4:], redis_data['dob'][2:4], redis_data['dob'][:2]))               
            userCreationData['name'] = redis_data['name']
            userCreationData['gender'] = redis_data['gender']
            userCreationData['uid_token'] = uid_token
            userCreationData['created_by'] = parent_digilockerid
            userCreationData['mobile'] = redis_data['mobile']
            userCreationData['relation'] = redis_data['relation']
            mqdata = {}
            mqdata['data'] = userCreationData
            
            rmq_status = RabbitmqRegisterFamily.createUser(mqdata)
            if rmq_status['status'] == 1:
                #delete the redis data 
                self.rs.remove(key= parent_digilockerid+'_'+redis_data['txn']+'_family_details')
                return {"status": "success","rmq_status":rmq_status['msg']}
            else:
                return {"status": "error","rmq_status":rmq_status['msg']}
        except Exception as e:
            print(str(e))
            return {"status": "error", "error_description": str(e)}
    
    
    def checkForAccountExist(self, uid_token):
        try:
            if uid_token:
                res = MongoLib.find(mongo_collection_users,{'uid_token':uid_token})
                for data in res:
                    return data
            else:
                return {"status": "error", "error_description": "error"}        
        except Exception as e:
            print(str(e))
            return {"status": "error", "error_description": str(e)}

    def check_unique_uuid(self, txnid):
        try:
            if txnid:
                res = MongoLib.find(mongo_collection_users,{'digilockerid':txnid})
                for data in res:
                    if data: 
                        return False
                return txnid
            else:
                return False        
        except Exception as e:
            print(str(e))
            return False

    def form_validation(self, aadhaar, name, dob, gender, relation, mobile):
        try:
            valid_aadhaar = Validation.aadhaar_validation(aadhaar)
            valid_name = Validation.name_validation(name)
            valid_dob = Validation.dob_validation(dob)
            valid_gender = Validation.gender_validation(gender)
            valid_relation = Validation.relation_validation(relation)
            valid_mobile = Validation.mobile_validation(mobile)
            
            if valid_aadhaar[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_aadhaar[1]['error_description']}
            
            elif valid_name[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_name[1]['error_description']}
            
            elif valid_dob[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_dob[1]['error_description']}
            
            elif valid_gender[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_gender[1]['error_description']}
            
            elif valid_relation[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_relation[1]['error_description']}
            
            elif valid_mobile[1]['status'] == 'error':
                return {'status': 'error', 'error_description': valid_mobile[1]['error_description']}
            
            else:
                return {'status':'success'}
            
        except Exception as e:
            return {"status": "error", "error_description": str(e)}
        
    def validate_demoauth():
        return True