import os

import copy
import json
import argparse
import requests
import sqlite3
import time
import boto3
import uuid
from decimal import Decimal

import KCALLMNutritionUtilities
import KCALLMActivityUtilities
import KCALLMPrompt
import KCALLMEngine
import KCALLMConst
import KCALLMCore
import KCADBProcessorUtilities as KCAProc
import KCALLMTrace as KCATrace




def execute(text, imagePath, image64, comment, appId, device, version, age, gender, longitude, latitude, test):

    # Misc
    start_time = time.time()
    
    KCATrace.TRACE("Input text: " + text)

    # Query
    jresult = None

    # Model
    model = KCALLMCore.getDefaultModel()

    # Run LLM
    omess = executeLLMSingle(text, imagePath, image64, comment, model)

    # Error
    if omess == None:
        return None

    # Results
    nbnut = 0
    try:
        nbnut = len(omess['solutions']['ingredients'])
    except:
        nbnut = 0
    nbact = 0
    try:
        nbact = len(omess['solutions']['activity'])
    except:
        nbact = 0

    # Build message
    end_time = time.time()
    omess["cputime"] = end_time - start_time  # in seconds

    KCATrace.TRACE("")
    KCATrace.TRACE("--------------------------------- final result -----------------------------------")
    KCATrace.TRACE(omess)
    KCATrace.TRACE("----------------------------------------------------------------------------------")
    scpu = "LLM CPU Time: " + str(omess["cputime"])
    KCATrace.TRACE(scpu)

    # Save info in dynamo DB
    if text != "" and test == 0:
        
        # Read keys
        AWS_ACCESS_KEY_ID = ''
        AWS_SECRET_ACCESS_KEY = ''

        # keyPath = "E:\\wamp\\www\\apps\\3d-minded\\profile\\M3Dkeys.json"
        keyPath = os.path.join('keys', 'M3Dkeys.json')
        with open(keyPath, 'r', encoding='utf-8') as f:
            keys = json.load(f)
            AWS_ACCESS_KEY_ID = keys['AWS_ACCESS_KEY_ID']
            AWS_SECRET_ACCESS_KEY = keys['AWS_SECRET_ACCESS_KEY']
            f.close()

        # Declare
        session = None
        regName = 'eu-west-3' # Paris
        session = boto3.Session(
            aws_access_key_id = AWS_ACCESS_KEY_ID,
            aws_secret_access_key = AWS_SECRET_ACCESS_KEY,
            region_name = regName
            ) 
        dynamodb = session.resource('dynamodb')
        table = dynamodb.Table('KCALME_PROMPT_V1')

        # Prepare result
        currentTime = time.time()
        result = {}
        result["V_RecordTime"] = int(time.time())
        result["V_UUID"] = str(uuid.uuid4()).upper()
        result["V_Prompt"] = text
        result["V_Device"] = device
        result["V_NutritionCount"] = nbnut
        result["V_ActivityCount"] = nbact
        result["V_AppId"] = appId
        result["V_Age"] = age
        result["V_Gender"] = gender
        result["V_Longitude"] = Decimal(longitude)
        result["V_Latitude"] = Decimal(latitude)
        result["V_Results"] = json.dumps(omess)
        
        # Insert item into table
        response = table.put_item(
           Item = result
        )

        # For tracking
        omess["uuid"] = result["V_UUID"]
        

    # Return result
    return omess



def executeLLMSingle(text, imagePath, image64, comment, model):

    # Read arguments
    dataLocation = os.path.join("__deriveddata__", "DerivedObjects", "Data")
    pictosPath = os.path.join("__deriveddata__", "DerivedObjects", "FoodPictos")
    dbPath = os.path.join(dataLocation, "KcalMeDB_fr.sl3")
    dbEmbeddingPath = os.path.join(dataLocation, "embeddingDB.sl3")
    pictoPath = os.path.join(dataLocation, "PictoMatcherNetNG_fr.json")
    sportGrounding = os.path.join(dataLocation, "DerivedSportMET.json")
    nutritionGrounding = os.path.join(dataLocation, "NutritionGroundingDico.json")

    KCATrace.TRACE("DB path: " + dbPath)
    KCATrace.TRACE("Picto path: " + pictoPath)
    KCATrace.TRACE("Sport grounding path: " + sportGrounding)

    # Read voca
    jVoca = {}
    with open(pictoPath, 'r', encoding='utf-8') as f:
        jVoca = json.load(f)
    f.close()

    # Run
    KCATrace.TRACE("==================================================================================================================================")
    KCATrace.TRACE("Prompt from user: " + text)
    KCATrace.TRACE("==================================================================================================================================")

    # Intentify the list of intents
    listIntents = KCALLMConst.getIntentList()
    intents = KCALLMEngine.getIntentsFromPrompt(listIntents, text, image64, model)

    # Loop on intents
    omess = {}
    omess["prompt"] = text
    omess["model"] = model
    omess["imagePath"] = imagePath
    omess["intents"] = copy.deepcopy(intents)
    omess["solutions"] = {'nutrition': [], 'activity': [], 'response': {}}
    nbnut = 0
    nbact = 0
    for intent in intents:

        sols = []
        mapper = {}

        #---------------------------------------------------
        # INTENT FOOD
        #---------------------------------------------------
        if intent == KCALLMConst.INTENT_TEXT_TO_FOOD or intent == KCALLMConst.INTENT_IMAGE_TO_FOOD or intent == KCALLMConst.INTENT_NUTRITION_QUESTION:

            # Read sport grounding
            mapper['type'] = []
            portraitRobot = ''

            # First step for food question: identify the foods
            effectiveIntent = intent
            if intent == KCALLMConst.INTENT_NUTRITION_QUESTION:
                effectiveIntent = KCALLMConst.INTENT_TEXT_TO_FOOD

            prompt = KCALLMPrompt.getPreprompt(text, mapper, effectiveIntent, portraitRobot)

            # Dump
            if intent == KCALLMConst.INTENT_IMAGE_TO_FOOD:
                print("Image to be analyzed: " + imagePath)
                
            # Run query
            jresult = KCALLMEngine.runLLM(prompt, image64, model)

            KCATrace.TRACE("")
            KCATrace.TRACE("--------------------------------- LLM result -----------------------------------")
            KCATrace.TRACE(jresult)
            KCATrace.TRACE("--------------------------------------------------------------------------------")
            sols = KCALLMNutritionUtilities.getBestSolutions(jresult["response"], dbPath, dbEmbeddingPath, jVoca)

            omess["solutions"]["nutrition"] = sols

            # Now solve the question
            if intent == KCALLMConst.INTENT_NUTRITION_QUESTION:

                # Extract the portrait robots
                portraitRobot = KCALLMNutritionUtilities.extractPortraitRobots(sols, dbPath, pictosPath)

                # Build prompt
                mapper['name'] = []
                prompt = KCALLMPrompt.getPreprompt(text, mapper, intent, portraitRobot)

                # Run query
                jresult = KCALLMEngine.runLLM(prompt, image64, model, False)

                KCATrace.TRACE("")
                KCATrace.TRACE("--------------------------------- LLM result -----------------------------------")
                KCATrace.TRACE(jresult)
                KCATrace.TRACE("--------------------------------------------------------------------------------")

                resp = {"type": "text", "data": jresult["response"]}
                omess["solutions"]["response"] = copy.deepcopy(resp)

            
        #---------------------------------------------------
        # INTENT SPORT
        #---------------------------------------------------
        elif intent == KCALLMConst.INTENT_TEXT_TO_ACTIVITY:

            # Read sport grounding
            mapper['name'] = []
            portraitRobot = ''
            with open(sportGrounding, 'r', encoding='utf-8') as f:
                jSports = json.load(f)
                for sp in jSports:
                    spn = sp["name"]["fr"]
                    mapper['name'].append(spn)
                f.close()

            # Build prompt
            prompt = KCALLMPrompt.getPreprompt(text, mapper, intent, portraitRobot)

            # Run query
            jresult = KCALLMEngine.runLLM(prompt, image64, model)

            # Retrieve a solution
            KCATrace.TRACE("")
            KCATrace.TRACE("--------------------------------- LLM result -----------------------------------")
            KCATrace.TRACE(jresult)
            KCATrace.TRACE("--------------------------------------------------------------------------------")
            sols = KCALLMActivityUtilities.getBestSolutions(jresult["response"], jSports)
            nbact = len(sols)

            omess["solutions"]["activity"] = sols

                

    return omess


