import math
import json
import os
import base64
import logging
import logging.handlers as handlers
from logging.handlers import RotatingFileHandler
import threading
import sqlite3
from collections import defaultdict
import collections
import datetime
import uuid
from flask_autoindex import AutoIndex
from skimage import io as iosk
from PIL import ImageOps, Image
from flask import Flask, jsonify, request, redirect
from flask_cors import CORS
from waitress import serve
import tensorflow.keras
import cv2
import numpy as np
import face_recognition
import dlib
import config
import sql
import urllib.request
# You can change this to any folder on your system
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif"}

app = Flask(__name__)
ppath = os.path.curdir  # update your own parent directory here
app = Flask(__name__)

AutoIndex(app, browse_root=ppath)

CORS(app)
# Load the model
model = tensorflow.keras.models.load_model("keras_model.h5")
logging.basicConfig(
    handlers=[RotatingFileHandler("faceauth.log", maxBytes=10485760, backupCount=10)],
    level=logging.DEBUG,
    format='"%(asctime)s -[Face Recogntion] - %(levelname)-7.7s %(message)s',
    datefmt="%Y-%m-%d %H:%M:%S",
)

# Path in server where Snapshot of the video is saved
# This image is agent or customer snapshot image from video.
# For Remote Survillience, it should be agent self video image
# For EKYC process, it should be cutomer image from live video.
sourceFaceImage = config.sourceFaceImage

# Path in the server where aadhar image is save
# This image is agent profile picture or any IC image like aadhar/EP/Pan card etc.
# For Remote Survillience, it should be agent profile picture
# For EKYC process, it should be any IC image like aadhar/EP/Pan card etc uploaded by customer.
destFaceImage = config.destFaceImage

face_auth_trasaction_details = (
    []
)  # face_found, Result, Result_reason, Score, Confidence (NOT USED)
requested_datetime = None
responded_datetime = None
image_path1 = None
image_path2 = None
originator = ""
profilePic_encodingData = defaultdict(collections.Counter)


def allowed_file(logFileName):
    return (
        "." in logFileName
        and logFileName.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
    )


@app.route("/test", methods=["GET", "POST"])
def upload_image():
    """
    This is the test method which accepts any 2 images and gives out the comparision result
    """
    logging.info("Upload_Image")
    # Check if a valid image file was uploaded
    if request.method == "POST":
        if "file1" not in request.files:
            logging.info("test1")
            return redirect(request.url)

        file = request.files["file1"]
        file2 = request.files["file2"]

        logging.info(str(file))
        logging.info(str(file2))

        if file.filename == "":
            logging.info("Filename not found")
            return redirect(request.url)
        requested_datetime = datetime.datetime.now()

        if file and allowed_file(file.filename):
            # The image file seems valid! Detect faces and return the result.
            return DetectAndCompareFacesInImages(
                file, file2, requested_datetime, "test", "test", "", ""
            )

    # If no valid image file was uploaded, show the file upload form:
    return """
    <!doctype html>
    <title>Is this a picture of Obama?</title>
    <h1>Upload pics and get the comparision results</h1>
    <form method="POST" enctype="multipart/form-data">
      <input type="file" name="file1">
      <input type="file" name="file2">
      <input type="submit" value="Upload">
    </form>
    """


def DetectAndCompareFacesInImages(
    sourceFileStream,
    destFileStream,
    requested_datetime,
    agentId,
    originator_name,
    source_url,
    destination_url,
):
    """
    Method to detect the faces in the image passed and do the comparision of those
    INPUT: 2 image paths 
    OUTPUT: json data of mathched information
    """

    try:
        # # Get face encodings for any faces in the uploaded image

        sourceFaceEncodingValue = face_recognition.face_encodings(
            face_recognition.load_image_file(sourceFileStream)
        )
        destFaceEncodingValue = face_recognition.face_encodings(
            face_recognition.load_image_file(destFileStream)
        )
        # enable the below logs if you want face encodings to be displyed in logs
        # logging.info("Image1 face encodings " + str(sourceFaceEncodingValue))
        # logging.info("Image2 face encodings " + str(destFaceEncodingValue))

        if len(sourceFaceEncodingValue) <= 0:
            logging.info(
                agentId + ":Face not found in source image " + sourceFileStream
            )
            return ProcessExceptionData(
                agentId,
                originator_name,
                "Face Not Found in Source Image",
                source_url,
                destination_url,
                requested_datetime,
                datetime.datetime.now(),
            )
        if len(destFaceEncodingValue) <= 0:
            logging.info(
                agentId + ":Face not found in destination image " + destFileStream
            )
            return ProcessExceptionData(
                agentId,
                originator_name,
                "Face Not Found in Destination Image",
                source_url,
                destination_url,
                requested_datetime,
                datetime.datetime.now(),
            )

        faceFound = False
        fpercentage = 0.0

        if len(sourceFaceEncodingValue) > 0 and len(destFaceEncodingValue) > 0:
            logging.info(
                agentId
                + ":DetectAndCompareFacesInImages : Face found in both source & destination images"
            )
            faceFound = True
            # See if the first face in the uploaded image matches the known face of Obama
            match_results = face_recognition.compare_faces(
                [sourceFaceEncodingValue[0]], destFaceEncodingValue[0]
            )
            face_distances = face_recognition.face_distance(
                [sourceFaceEncodingValue[0]], destFaceEncodingValue[0]
            )
            logging.info(
                agentId
                + ":DetectAndCompareFacesInImages : Face distance "
                + str(face_distances)
            )

            fpercentage = GetFaceComparisionPercentage(face_distances, agentId, 0.6)
            logging.info(
                agentId
                + ":DetectAndCompareFacesInImages : Percentage of face match "
                + str(fpercentage[0])
            )

        # Return the comparisionResult as json
        comparisionResult = {
            "face_found_in_image": faceFound,
            "face_authenticated_percentage": fpercentage[0] * 100,
            "face_isreal": 1,
        }
        # image.close()
        responded_datetime = datetime.datetime.now()
        threading.Thread(
            target=sql.save_faceauth_data,
            args=(
                requested_datetime,
                responded_datetime,
                source_url,
                destination_url,
                originator_name,
                agentId,
                "True",
                "Face found in Image",
                str(fpercentage[0] * 100),
                str(face_distances),
            ),
        ).start()

        return jsonify(comparisionResult)
    except Exception as ex:
        logging.info(
            agentId + ":Exception in DetectAndCompareFacesInImages : " + str(ex)
        )

        return ProcessExceptionData(
            agentId,
            originator_name,
            "Exception in DetectAndCompareFacesInImages",
            source_url,
            destination_url,
            requested_datetime,
            datetime.datetime.now(),
        )


def GetFaceComparisionPercentage(face_distance, agentId, face_match_threshold=0.6):
    """
    This method will give the percentage of match between
    the 2 image encodings with respect to the threshold
    """
    logging.info(
        agentId
        + ":GetFaceComparisionPercentage Face Distance"
        + str(face_distance)
        + ", Threshold "
        + str(face_match_threshold)
    )

    try:
        if face_distance > face_match_threshold:
            range = 1.0 - face_match_threshold
            linear_val = (1.0 - face_distance) / (range * 2.0)
            return linear_val
        else:
            range = face_match_threshold
            linear_val = 1.0 - (face_distance / (range * 2.0))
            return linear_val + (
                (1.0 - linear_val) * math.pow((linear_val - 0.5) * 2, 0.2)
            )
    except Exception as ex:
        logging.info("Exception in GetFaceComparisionPercentage : " + str(ex))


@app.route("/VerifyFaceImages", methods=["GET", "POST"])
def VerifyFaceImages():
    """
    Method to verify face images requested by client app
    INPUT: snaptype (url,base64), snapdata, pptype(url,base64), ppdata, agentid, orginator
               ppType means - ProfilePIC
    OUTPUT: json data of mathched information
    """
    try:
        requested_datetime = datetime.datetime.now()
        defaultSourceFilePath = sourceFaceImage
        defaultDestFilePath = destFaceImage

        agent_id = request.json["agentId"]
        originator_name = request.json["originator"]
        snap_data = request.json["snapdata"]
        pp_data = request.json["ppdata"]
        snap_type = request.json["snaptype"]
        pp_type = request.json["pptype"]
        isrealface = request.json["isrealface"]
        logging.info(
            agent_id
            + ":VerifyFaceImages : snaptype: "
            + snap_type
            + ", pptype: "
            + pp_type
            + ", agentId: "
            + agent_id
            + ", ppdata: "
            + pp_data
            + ", originator: "
            + originator_name
            + ", isRealFace: "
            + isrealface
        )

        # Check if snapdata or ppdata or agentId is empty.
        #  If empty return back with exception to the client
        if snap_data == "" or pp_data == "" or agent_id == "":
            logging.info(
                agent_id
                + ":VerifyFaceImages snapdata: "
                + snap_data
                + " ppdata: "
                + pp_data
                + " agentId: "
                + agent_id
            )
            return ProcessExceptionData(
                agent_id,
                originator_name,
                "SnapData or PpData or AgentId is empty",
                "",
                "",
                datetime.datetime.now(),
                datetime.datetime.now(),
            )

        # check if the originator has value or not. If not, assing TMAC to it
        request_json_data = json.loads(json.dumps(request.get_json()))
        if "originator" in request_json_data and originator_name != "":
            originator = originator_name
        else:
            originator = "TMAC"

        if snap_type == "url":
            defaultSourceFilePath = defaultSourceFilePath + snap_data
            source_filename = snap_data
        else:
            # base64
            if snap_data != "":
                datetime_stamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
                source_filename = agent_id + "_" + datetime_stamp + ".png"
                defaultSourceFilePath = defaultSourceFilePath + source_filename

                with open(defaultSourceFilePath, "wb") as fh:
                    fh.write(base64.b64decode(snap_data))

                # detect if this image is a real or fake image based on the configuration set
                if isrealface != "1":
                    logging.info(
                        agent_id + ": isRealFace is 0. Check for liveness in the image"
                    )
                    if config.detect_liveness:
                        logging.info(
                            agent_id + " :detect Liveness is enabled in the config"
                        )
                        isReal = detect_liveness(defaultSourceFilePath, False, False)
                        if not isReal:
                            logging.info(
                                agent_id
                                + ": isReal is 0. Fake Image. Return to the client"
                            )
                            retData = {
                                "face_found_in_image": 0,
                                "face_authenticated_percentage": 0,
                                "face_isreal": 0,
                            }
                            return jsonify(retData)

        if pp_type == "url":
            destination_filename = pp_data
            defaultDestFilePath = defaultDestFilePath + destination_filename
            source_image_url_path = config.sourceFaceImageURL + source_filename
            if config.is_profilepic_url:
                urllib.request.urlretrieve(config.destFaceImageURL + pp_data, defaultDestFilePath)
                source_image_url_path = snap_data
        else:
            # base64
            uuid_datetime = (
                str(uuid.uuid4())
                + "_"
                + datetime.datetime.now().strftime("%Y%m%d%H%M%S")
            )
            destination_filename = uuid_datetime + ".png"
            defaultDestFilePath = defaultDestFilePath + destination_filename
            with open(defaultDestFilePath, "wb") as fh:
                fh.write(base64.b64decode(pp_data))
        
        dest_image_url_path = config.destFaceImageURL + pp_data

        return_data = DetectAndCompareFacesInImages(
            defaultDestFilePath,
            defaultSourceFilePath,
            requested_datetime,
            agent_id,
            originator,
            dest_image_url_path,
            source_image_url_path,
        )
        logging.info(agent_id + ":VerifyFaceImages Response: " + str(return_data))

        return return_data

    except Exception as ex:
        logging.info(agent_id + ":Exception in VerifyFaceImages : " + str(ex))

        return ProcessExceptionData(
            agent_id,
            originator_name,
            "Exception in VerifyFaceImages",
            "",
            "",
            datetime.datetime.now(),
            datetime.datetime.now(),
        )


def ProcessExceptionData(
    agentId,
    originator_name,
    exception_message,
    source_url,
    destination_url,
    request_datetime,
    response_datetime,
):
    """
    This method is a generic method whenever there is an exception raised.
    Accepts the message and other parameters and returns back the client
    """
    try:
        logging.info(agentId + ":ProcessExceptionData")
        comparisionResult = {
            "face_found_in_image": 0,
            "face_authenticated_percentage": 0,
            "face_isreal": 0,
        }

        threading.Thread(
            target=sql.save_faceauth_data,
            args=(
                request_datetime,
                response_datetime,
                source_url,
                destination_url,
                originator_name,
                agentId,
                "False",
                exception_message,
                "0",
                "0",
            ),
        ).start()
        logging.info(
            agentId + ":ProcessExceptionData Response: " + str(comparisionResult)
        )
        return jsonify(comparisionResult)
    except Exception as identifier:
        logging.info(agentId + ":Exception in ProcessExceptionData" + str(identifier))
        comparisionResult = {
            "face_found_in_image": 0,
            "face_authenticated_percentage": 0,
        }
        return jsonify(comparisionResult)


def detect_faces(image, name):
    try:
        logging.info("detect_faces " + str(name))
        # Create a face detector
        face_detector = dlib.get_frontal_face_detector()

        # Run detector and get bounding boxes of the faces on image.
        detected_faces = face_detector(image, 1)
        logging.info("Number of faces detected: {}".format(len(detected_faces)))
        for i, d in enumerate(detected_faces):
            logging.info(
                "Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
                    i, d.left(), d.top(), d.right(), d.bottom()
                )
            )
            img = cv2.imread(name)
            crop = img[d.top() : d.bottom(), d.left() : d.right()]
            resize = cv2.resize(crop, (200, 200))
            cv2.imwrite(name, resize)
            cv2.waitKey(0)
            return resize
    except Exception as identifier:
        logging.info("Exception in detect_faces " + str(identifier))


def detect_liveness(imagename, isReturnJson, isUrl):
    try:
        logging.info("detect liveness")
        # logging.info("detect_liveness" + str(imagename))
        if isUrl:
            image = iosk.imread(imagename)
        else:
            image = dlib.load_rgb_image(imagename)
        detected_faces = detect_faces(image, imagename)
        # Disable scientific notation for clarity
        np.set_printoptions(suppress=True)
        
        logging.info("print1")

        # Load the model
        # model = tensorflow.keras.models.load_model("keras_model.h5")

        # Create the array of the right shape to feed into the keras model
        # The 'length' or number of images you can put into the array is
        # determined by the first position in the shape tuple, in this case 1.
        data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
        logging.info("print2")

        # Replace this with the path to your image
        # image = Image.open(imagename)
        logging.info(detected_faces)
        image = Image.fromarray(np.uint8(detected_faces)).convert("RGB")
        logging.info("print3")

        # resize the image to a 224x224 with the same strategy as in TM2:
        # resizing the image to be at least 224x224 and then cropping from the center
        size = (224, 224)
        image = ImageOps.fit(image, size, Image.ANTIALIAS)
        logging.info("print4")

        # turn the image into a numpy array
        image_array = np.asarray(image)
        logging.info("print5")

        # Normalize the image
        normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
        logging.info("print6")

        # Load the image into the array
        data[0] = normalized_image_array
        logging.info("print7")

        # run the inference
        prediction = model.predict(data)
        logging.info(prediction)
        real = prediction[0][0]
        fake = prediction[0][1]
        if isReturnJson:
            if abs(real) >= config.face_liveness_threshold:
                # return Real Face
                retData = {"isReal": "Real Face"}
                return jsonify(retData)
            elif abs(fake) >= config.face_liveness_threshold:
                # return Fake Face
                retData = {"isReal": "Fake Face"}
                return jsonify(retData)
            else:
                # return Not Sure
                retData = {"isReal": "Not Sure"}
                return jsonify(retData)
        if abs(real) >= config.face_liveness_threshold:
            return True
        else:
            return False
        return real, fake
    except Exception as identifier:
        logging.info("Exception in detect_liveness " + str(identifier))


@app.route("/VerifyFaceLiveness", methods=["GET", "POST"])
def VerifyFaceLiveness():
    try:
        logging.info("VerifyFaceLiveness: ")
        face_livenessData = request.json["facedata"]
        sourceFaceImage = config.sourceFaceImage
        sourceFaceImage = sourceFaceImage + str(uuid.uuid4()) + "_live" + ".png"
        with open(sourceFaceImage, "wb") as fh:
            fh.write(base64.b64decode(face_livenessData))
        liveness_data = detect_liveness(sourceFaceImage, True, False)
        return liveness_data
    except Exception as identifier:
        logging.info("Exception in VerifyFaceLiveness: " + str(identifier))
        return jsonify("Oops! Something went wrong")


@app.route("/VerifyFaceAuthWithEncoding", methods=["GET", "POST"])
def VerifyFaceAuthWithEncoding():
    """
    Method to verify face images requested by client app
    INPUT: snaptype (url,base64), snapdata, pptype(url,base64), ppdata, agentid, orginator
               ppType means - ProfilePIC
    OUTPUT: json data of mathched information
    """
    try:
        requested_datetime = datetime.datetime.now()

        requested_datetime = datetime.datetime.now()

        agent_id = request.json["lanId"]
        originator_name = request.json["originator"]
        snap_encoded_data = request.json["snapEncodedData"]
        isrealface = request.json["isRealFace"]
        snap_data_url = request.json["snapDataUrl"]

        logging.info(
            agent_id
            + ":VerifyFaceAuthWithEncoding Request: "
            + "lanId: "
            + agent_id
            + ", originator: "
            + originator_name
            + ", isRealFace: "
            + isrealface
            + ", Snapdataurl: "
            + snap_data_url
        )

        # Check if snapdata  or agentId is empty. If empty return back with exception to the client
        if snap_encoded_data == "" or agent_id == "" or snap_data_url == "":
            logging.info(
                agent_id
                + ":VerifyFaceAuthWithEncoding snapdata: "
                + snap_encoded_data
                + " lanId: "
                + agent_id
            )
            return ProcessExceptionData(
                agent_id,
                originator_name,
                "snap_encoded_data or snap_data_url or lanId is empty",
                "",
                "",
                datetime.datetime.now(),
                datetime.datetime.now(),
            )

        if snap_data_url != "":
            # detect if this image is a real or fake image based on the configuration set
            if isrealface != "1":
                logging.info(
                    agent_id + ": isRealFace is 0. Check for liveness in the image"
                )
                if config.detect_liveness:
                    logging.info(
                        agent_id + " :detect Liveness is enabled in the config"
                    )
                    isReal = detect_liveness(snap_data_url, False, True)
                    if not isReal:
                        logging.info(
                            agent_id + ": isReal is 0. Fake Image. Return to the client"
                        )
                        retData = {
                            "face_found_in_image": 0,
                            "face_authenticated_percentage": 0,
                            "face_isreal": 0,
                        }
                        return jsonify(retData)
        
        if agent_id in profilePic_encodingData.keys():
            logging.info(agent_id + " is present in the dictionary")
        else:
            logging.info(
                agent_id + " is not found in the dictionary. Update ProfilePic from OCM"
            )
            comparisionResult = {
                "face_found_in_image": 0,
                "face_authenticated_percentage": 0,
                "face_isreal": 0,
            }
            source_image_url_path = ""
            dest_image_url_path = ""
            responded_datetime = datetime.datetime.now()
            threading.Thread(
                target=sql.save_faceauth_data,
                args=(
                    requested_datetime,
                    responded_datetime,
                    source_image_url_path,
                    dest_image_url_path,
                    originator_name,
                    agent_id,
                    "False",
                    "ProfilePicEncodings not found",
                    "0",
                    "0",
                ),
            ).start()
            return jsonify(comparisionResult)

        dest_image_url_path = profilePic_encodingData[agent_id]["url"]
        source_image_url_path = snap_data_url

        logging.info(agent_id+": Profile Pic URL: "+str(dest_image_url_path))

        destFaceEncodingValue = profilePic_encodingData[agent_id]["encoding"]
        if isinstance(destFaceEncodingValue, str):
            lst = json.loads(destFaceEncodingValue)
            destFaceEncodingValue = [np.array(lst)]

        logging.info('aaaa')
        sourceFaceEncodingValue = [np.array(snap_encoded_data)]

        faceFound = True
        # sourceFaceEncodingValue = sourceFaceEncodingValue[0].astype("float64")
        match_results = face_recognition.compare_faces(
            [destFaceEncodingValue], sourceFaceEncodingValue[0]
        )
        face_distances = face_recognition.face_distance(
            [destFaceEncodingValue], sourceFaceEncodingValue[0]
        )
        logging.info(
            agent_id
            + ":VerifyFaceAuthWithEncoding : Face distance "
            + str(face_distances)
        )

        fpercentage = GetFaceComparisionPercentage(face_distances, agent_id, 0.6)
        logging.info(
            agent_id
            + ":VerifyFaceAuthWithEncoding : Percentage of face match "
            + str(fpercentage[0])
        )

        # Return the comparisionResult as json
        comparisionResult = {
            "face_found_in_image": faceFound,
            "face_authenticated_percentage": fpercentage[0] * 100,
            "face_isreal": 1,
        }
        responded_datetime = datetime.datetime.now()
        threading.Thread(
            target=sql.save_faceauth_data,
            args=(
                requested_datetime,
                responded_datetime,
                source_image_url_path,
                dest_image_url_path,
                originator_name,
                agent_id,
                "True",
                "Face found in Image",
                str(fpercentage[0] * 100),
                str(face_distances),
            ),
        ).start()

        logging.info(
            agent_id + ":VerifyFaceAuthWithEncoding Response: " + str(comparisionResult)
        )

        return jsonify(comparisionResult)

    except Exception as ex:
        logging.info(agent_id + ":Exception in VerifyFaceAuthWithEncoding : " + str(ex))

        return ProcessExceptionData(
            agent_id,
            originator_name,
            "Exception in VerifyFaceAuthWithEncoding " + str(ex),
            "",
            "",
            datetime.datetime.now(),
            datetime.datetime.now(),
        )

# def VerifyFaceAuthWithEncoding():
    # """
    # Method to verify face images requested by client app
    # INPUT: snaptype (url,base64), snapdata, pptype(url,base64), ppdata, agentid, orginator
               # ppType means - ProfilePIC
    # OUTPUT: json data of mathched information
    # """
    # try:
        # requested_datetime = datetime.datetime.now()

        # requested_datetime = datetime.datetime.now()

        # agent_id = request.json["lanId"]
        # originator_name = request.json["originator"]
        # snap_encoded_data = request.json["snapEncodedData"]
        # isrealface = request.json["isRealFace"]
        # snap_data_url = request.json["snapDataUrl"]

        # logging.info(
            # agent_id
            # + ":VerifyFaceAuthWithEncoding Request: "
            # + "lanId: "
            # + agent_id
            # + ", originator: "
            # + originator_name
            # + ", isRealFace: "
            # + isrealface
            # + ", Snapdataurl: "
            # + snap_data_url
        # )

        # # Check if snapdata  or agentId is empty. If empty return back with exception to the client
        # if snap_encoded_data == "" or agent_id == "" or snap_data_url == "":
            # logging.info(
                # agent_id
                # + ":VerifyFaceAuthWithEncoding snapdata: "
                # + snap_encoded_data
                # + " lanId: "
                # + agent_id
            # )
            # return ProcessExceptionData(
                # agent_id,
                # originator_name,
                # "snap_encoded_data or snap_data_url or lanId is empty",
                # "",
                # "",
                # datetime.datetime.now(),
                # datetime.datetime.now(),
            # )

        # if snap_data_url != "":
            # # detect if this image is a real or fake image based on the configuration set
            # if isrealface != "1":
                # logging.info(
                    # agent_id + ": isRealFace is 0. Check for liveness in the image"
                # )
                # if config.detect_liveness:
                    # logging.info(
                        # agent_id + " :detect Liveness is enabled in the config"
                    # )
                    # isReal = detect_liveness(snap_data_url, False, True)
                    # if not isReal:
                        # logging.info(
                            # agent_id + ": isReal is 0. Fake Image. Return to the client"
                        # )
                        # retData = {
                            # "face_found_in_image": 0,
                            # "face_authenticated_percentage": 0,
                            # "face_isreal": 0,
                        # }
                        # return jsonify(retData)

        # dest_image_url_path = profilePic_encodingData[agent_id]["url"]
        # source_image_url_path = snap_data_url

        # # logging.info(agent_id+": Profile Pic URL: "+str(dest_image_url_path))

        # destFaceEncodingValue = profilePic_encodingData[agent_id]["encoding"]
        # # if isinstance(destFaceEncodingValue, str):
        # #     lst = json.loads(destFaceEncodingValue)
        # #     destFaceEncodingValue = [np.array(lst)]

        # sourceFaceEncodingValue = [np.array(snap_encoded_data)]

        # faceFound = True
        # # sourceFaceEncodingValue = sourceFaceEncodingValue[0].astype("float64")
        # match_results = face_recognition.compare_faces(
            # [destFaceEncodingValue], sourceFaceEncodingValue[0]
        # )
        # face_distances = face_recognition.face_distance(
            # [destFaceEncodingValue], sourceFaceEncodingValue[0]
        # )
        # logging.info(
            # agent_id
            # + ":VerifyFaceAuthWithEncoding : Face distance "
            # + str(face_distances)
        # )

        # fpercentage = GetFaceComparisionPercentage(face_distances, agent_id, 0.6)
        # logging.info(
            # agent_id
            # + ":VerifyFaceAuthWithEncoding : Percentage of face match "
            # + str(fpercentage[0])
        # )

        # # Return the comparisionResult as json
        # comparisionResult = {
            # "face_found_in_image": faceFound,
            # "face_authenticated_percentage": fpercentage[0] * 100,
            # "face_isreal": 1,
        # }
        # responded_datetime = datetime.datetime.now()
        # threading.Thread(
            # target=sql.save_faceauth_data,
            # args=(
                # requested_datetime,
                # responded_datetime,
                # source_image_url_path,
                # dest_image_url_path,
                # originator_name,
                # agent_id,
                # "True",
                # "Face found in Image",
                # str(fpercentage[0] * 100),
                # str(face_distances),
            # ),
        # ).start()

        # logging.info(
            # agent_id + ":VerifyFaceAuthWithEncoding Response: " + str(comparisionResult)
        # )

        # return jsonify(comparisionResult)

    # except Exception as ex:
        logging.info(agent_id + ":Exception in VerifyFaceAuthWithEncoding : " + str(ex))

        return ProcessExceptionData(
            agent_id,
            originator_name,
            "Exception in VerifyFaceAuthWithEncoding " + str(ex),
            "",
            "",
            datetime.datetime.now(),
            datetime.datetime.now(),
        )


@app.route("/AddOrUpdateProfilePic", methods=["GET", "POST"])
def AddOrUpdateProfilePic():
    """
    Method to update the encoding of profile pic of user into a pickle dict. 
    INPUT: agentId, Image URL
    OUTPUT: True/False
    """
    try:
        global profilePic_encodingData

        conn = sqlite3.connect("profilePicEncoding.db")
        cursor = conn.cursor()

        agent_id = request.json["lanId"]
        profilepic = request.json["profilePic"]
        request_type = request.json["requestType"]
        # logging.info(
        # agent_id + ": AddOrUpdateProfilePic: Profile Pic URL: " + profilepic)

        if request_type == "url":
            profilePicture = iosk.imread(profilepic)
            profilePicEncoding = face_recognition.face_encodings(profilePicture)
        else:
            profilePicEncoding = get_face_encoding_from_base64(profilepic)
        json_encoded_data = json.dumps(profilePicEncoding[0].tolist())

        data_to_be_inserted = (agent_id, profilepic, json_encoded_data)

        cursor.execute(
            "SELECT AGENTID FROM AGENTPROFILEPICDETAILS WHERE AGENTID = ?", (agent_id,)
        )
        ROW = cursor.fetchone()

        if ROW is None:
            sqlite_insert_query = """INSERT INTO AGENTPROFILEPICDETAILS
                          (AgentId, PROFILEPICURL, ENCODINGDATA) 
                           VALUES 
                          (?,?,?)"""
            cursor.execute(sqlite_insert_query, data_to_be_inserted)
            conn.commit()
        else:
            data_to_be_inserted = (profilepic, json_encoded_data, agent_id)
            sqlite_insert_query = """UPDATE AGENTPROFILEPICDETAILS SET PROFILEPICURL=?, ENCODINGDATA=? WHERE AGENTID=?"""
            cursor.execute(sqlite_insert_query, data_to_be_inserted)
            conn.commit()
        conn.close()
        profilePic_encodingData[agent_id]["encoding"] = profilePicEncoding[0]
        profilePic_encodingData[agent_id]["url"] = profilepic

        return jsonify(True)
    except Exception as ex:
        logging.info(agent_id + ": Exception in AddOrUpdateProfilePic: " + str(ex))
        return jsonify(False)

@app.route("/RegisterDataWithFace", methods=["GET", "POST"])
def RegisterDataWithFace():
    try:
        logging.info("RegisterDataWithFace")

        userName = request.json["userName"]
        firstName = request.json["firstName"]
        lastName = request.json["lastName"]
        # avayaLoginId = request.json["avayaLoginId"]
        profilepic = request.json["profilePic"]

        defaultDestFilePath = config.destFaceImage

        requested_datetime = datetime.datetime.now()
        with open(defaultDestFilePath + userName + ".png", "wb") as fh:
                fh.write(base64.b64decode(profilepic))
        
        image = face_recognition.load_image_file(defaultDestFilePath + userName + ".png")
        face_locations = face_recognition.face_locations(image)

        if len(face_locations) is 0:
            return jsonify("No Face Found")
        # do sql insertion with the above data
        ret = sql.insert_agent_details(userName,firstName,lastName,profilepic)

        return jsonify(ret)

    except Exception as identifier:
        logging.info(identifier)
        return jsonify("Failure")


def get_face_encoding_from_base64(base64String):
    logging.info("get_face_encoding_from_base64")
    nparr = np.frombuffer(base64.b64decode(base64String.encode("utf-8")), np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    image_encodeing = face_recognition.face_encodings(rgb_img)
    # print(image_encodeing)
    return image_encodeing


def initialize_db():
    try:
        logging.info('loading db')
        global profilePic_encodingData
        conn = sqlite3.connect("profilePicEncoding.db")
        cursor = conn.cursor()
        cursor = cursor.execute(
            "SELECT AGENTID,PROFILEPICURL,ENCODINGDATA FROM AGENTPROFILEPICDETAILS"
        )
        rows = cursor.fetchall()
        conn.close()
        for row in rows:
            profilePic_encodingData[row[0]]["url"] = row[1]
            profilePic_encodingData[row[0]]["encoding"] = np.array(json.loads(row[2]))
        logging.info('loading db completed')
    except Exception as ex:
        logging.info("Exception during initialization DB " + str(ex))


if __name__ == "__main__":
    if config.is_load_profilepic_onstartup:
        sql.load_profilepic()
    initialize_db()
    serve(
        app,
        host="0.0.0.0",
        port=config.port,
        threads=8,
        cleanup_interval=15,
        channel_timeout=60,
    )
    logging.info("Application started")
