from typing import Any, Coroutine

from fastapi import Request, Response, status
from fastapi.responses import JSONResponse
from .blackbox import Blackbox

import chromadb
from chromadb.utils import embedding_functions
import logging
from ..log.logging_time import logging_time
import re

logger = logging.getLogger
DEFAULT_COLLECTION_ID = "123"

from injector import singleton
@singleton
class ChromaQuery(Blackbox):

    def __init__(self, *args, **kwargs) -> None:
        # config = read_yaml(args[0])
        # load chromadb and embedding model
        self.embedding_model_1 = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="/home/administrator/Workspace/Models/BAAI/bge-large-zh-v1.5", device = "cuda")
        self.embedding_model_2 = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="/home/administrator/Workspace/Models/BAAI/bge-large-en-v1.5", device = "cuda")
        self.client_1 = chromadb.HttpClient(host='172.16.5.8', port=7000)
        # self.client_2 = chromadb.HttpClient(host='10.6.82.192', port=8000)

    def __call__(self, *args, **kwargs):
        return self.processing(*args, **kwargs)

    def valid(self, *args, **kwargs) -> bool:
        data = args[0]
        return isinstance(data, list)

    # @logging_time(logger=logger)
    def processing(self, question: str, settings: dict) -> str:

        if settings is None:
            settings = {}
        
        usr_question = question

        # # chroma_query settings
        chroma_embedding_model = settings.get("chroma_embedding_model")
        chroma_host = settings.get("chroma_host")
        chroma_port = settings.get("chroma_port")
        chroma_collection_id = settings.get("chroma_collection_id")
        chroma_n_results = settings.get("chroma_n_results")

        if usr_question is None:
            return JSONResponse(content={"error": "question is required"}, status_code=status.HTTP_400_BAD_REQUEST)

        if chroma_embedding_model is None or chroma_embedding_model.isspace() or chroma_embedding_model == "":
            chroma_embedding_model = "/home/administrator/Workspace/Models/BAAI/bge-large-zh-v1.5"

        if chroma_host is None or chroma_host.isspace() or chroma_host == "":
            chroma_host = "172.16.5.8"
        
        if chroma_port is None or chroma_port.isspace() or chroma_port == "":
            chroma_port = "7000"
        
        if chroma_collection_id is None or chroma_collection_id.isspace() or chroma_collection_id == "":
            chroma_collection_id = "g2e"

        if chroma_n_results is None or chroma_n_results == "":
            chroma_n_results = 3

        # load client and embedding model from init
        if re.search(r"172.16.5.8", chroma_host) and re.search(r"7000", chroma_port):
            client = self.client_1
        else:
            client = chromadb.HttpClient(host=chroma_host, port=chroma_port)

        if re.search(r"/home/administrator/Workspace/Models/BAAI/bge-large-zh-v1.5", chroma_embedding_model):
            embedding_model = self.embedding_model_1
        elif re.search(r"/home/administrator/Workspace/Models/BAAI/bge-large-en-v1.5", chroma_embedding_model):
            embedding_model = self.embedding_model_2
        else:
            embedding_model = embedding_functions.SentenceTransformerEmbeddingFunction(model_name=chroma_embedding_model, device = "cuda")

        # load collection
        collection = client.get_collection(chroma_collection_id, embedding_function=embedding_model)

        print(usr_question)
        # query it
        results = collection.query(
            query_texts=[usr_question],
            n_results=chroma_n_results,    
        )

        # response = str(results["documents"] + results["metadatas"])
        # response = str(results["documents"])

        final_result = ''

        if results is not None:
            results_distances = results["distances"][0]

            #distance越高越不准确
            top_distance = 0.8

            
            for i in range(len(results_distances)):
                if results_distances[i] < top_distance:
                    final_result += results["documents"][0][i]

            print("\n final_result: ", final_result)

        return final_result


    async def fast_api_handler(self, request: Request) -> Response:
        try:
            data = await request.json()
        except:
            return JSONResponse(content={"error": "json parse error"}, status_code=status.HTTP_400_BAD_REQUEST)

        user_question = data.get("question")
        setting = data.get("settings")

        return JSONResponse(
            content={"response": self.processing(user_question, setting)},
            status_code=status.HTTP_200_OK)