from flask import request, url_for
from flask_api import FlaskAPI
from flask import jsonify
from flask import json
from flask import Response
from flask import send_from_directory, send_file
from flask_cors import CORS
import cv2
import tensorflow as tf
from tensorflow.keras import datasets, layers, models, regularizers
import numpy as np
import os
import sys
import datetime

sys.path.append(os.path.abspath("/home/verifier/database"))
import database

app = FlaskAPI(__name__)
CORS(app)
cassandraOperations = database.CassandraOperations()

#Title each block, clean and format code
IMG_SIZE = 100
CHECKPOINT_PATH = '/home/verifier/cloud/TrainedModel/cp.ckpt'
CATEGORIES = ['NandiniBlue', 'NandiniGoodLife', 'NandiniGreen', 'NandiniOrange', 'NandiniSlim']

def createModel():
    global cnn
    cnn = models.Sequential([
        layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 3)),
        layers.MaxPooling2D((2, 2)),
        
        layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'),
        layers.MaxPooling2D((2, 2)),
        
        layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu'),
        layers.MaxPooling2D((2, 2)),

        layers.Flatten(),

        layers.Dense(
            units=32,
            kernel_regularizer=regularizers.l1_l2(l1=1e-5, l2=1e-4),
            bias_regularizer=regularizers.l2(1e-4),
            activity_regularizer=regularizers.l2(1e-5)
        ),

        layers.Dense(5, activation='softmax')
    ])

    cnn.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    cnn.load_weights(CHECKPOINT_PATH)
    return cnn

def classify(imgPath):
    global cnn
    img = cv2.imread(imgPath)
    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))
    img = np.array(img).reshape(-1, IMG_SIZE, IMG_SIZE, 3)

    res = CATEGORIES[np.argmax(cnn.predict(img))]
    return res

def calculateVolume(weight):
    if weight >= 450 and weight <= 550:
        volume = 0.5 
    else:
        volume = 1
    return volume

def calculateCost(milktype, volume):
    if milktype == 'NandiniBlue':
        cost = 18
    elif milktype == 'NandiniOrange':
        cost = 20
    elif milktype == 'NandiniGreen':
        cost = 21
    elif milktype == 'NandiniGoodLife':
        cost = 23
    elif milktype == 'NandiniSlim':
        cost = 25
    else:
        cost = 0
    return cost*volume*2

@app.route('/receiveImages', methods=['POST'])
def receiveImages():
    print('Retreiving Image')
    if request is None:        
        print("Invalid request from Client")
    else:
        print("Received request: ",request.method)

    if request.method == 'POST':
        if request.files is None:
            print("No Image sent")
        else:
            print("- - - - ",request.files,"- - - -")
            receivedFiles = request.files['upload']
            receivedFiles.save(receivedFiles.filename)
        print("Image Saved successfully")
        return jsonify({'status': "success"}) 
    else:
        print("Not POST request")
        return jsonify({'status': 'Invalid method'})

@app.route('/getAllData', methods=['GET'])
def getAllData():
    cache = {}
    print('fetching all data')
    data = cassandraOperations.executeQuery("select * from milkdata.delivery")
    for item in data:
        cache[str(item.timestamp)] = str(item.prediction)

    return jsonify(cache)  


@app.route('/verify',methods=['POST'])
def verify():
    print("Detection started...")
    data = request.get_json()
    print(data)
    deviceName = data['devicename']
    timeData = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    imageData = data['imagename']
    weightData = data['weight']
    volumeData = calculateVolume(weightData)
    #run the model
    try:
        cnn = createModel()
        predictionResult = classify(imageData)
        costData = calculateCost(predictionResult, volumeData)
    except:
        cassandraOperations.executeQuery("INSERT INTO delivery(timestamp,device,image,weight,prediction,cost,volume) VALUES('{time}','{device}','{image}',{weight},'{prediction}','{cost}','{volume}');".format(time=timeData,device=deviceName,image=imageData,weight=weightData,prediction='Error',cost='Error',volume=volumeData,status='NotPaid'))
        return jsonify({'status': "unsuccessful","device":deviceName,"time":timeData,"Type":"Error"})
    
    #Do DB operations here
    #Add all items to table

    cassandraOperations.executeQuery("INSERT INTO delivery(timestamp,device,image,weight,prediction,cost,volume) VALUES('{time}','{device}','{image}',{weight},'{prediction}','{cost}','{volume}');".format(time=timeData,device=deviceName,image=imageData,weight=weightData,prediction=str(predictionResult),cost=costData,volume=volumeData,status='NotPaid'))

    #Handle exceptions for each case
    return jsonify({'status': "success","device":deviceName,"time":timeData,"Type":predictionResult})

#Create mode end points to retreive from DB (GET methods) or use DB directly in your application

if __name__ == '__main__':
    cassandraOperations.createSession('34.89.206.52')
    cassandraOperations.setLogger('INFO')
    cassandraOperations.createKeyspaceIfNotExists('milkdata')
    cassandraOperations.executeQuery('CREATE TABLE IF NOT EXISTS delivery(timestamp timestamp PRIMARY KEY, device text, image text, weight float,prediction text, cost float, volume float, status text);')
    app.run(host='0.0.0.0', port=50053)




