import time


def keyword_overlap(q1, q2):
    w1 = set(q1.split())
    w2 = set(q2.split())
    return len(w1 & w2) / len(w1 | w2) if (w1 | w2) else 0

def normalize(query):
    return query.lower().strip()

def estimate_tokens(text):
    return len(text.split())

class CacheMind:

   def __init__(self, embedding=None, vector_store=None, policy=None, threshold=0.8, llm=None, metrics=None):
        from .resolver import (resolve_embedding, resolve_vector_store, resolve_policy,)
        from .metrics import Metrics
        from .llm import DummyLLM

        self.embedder= resolve_embedding(embedding)
        self.store= resolve_vector_store(vector_store)
        self.policy= resolve_policy(policy, threshold)
        self.llm= llm or DummyLLM()
        self.metrics= metrics or Metrics()

   def __call__(self, text: str):
        return self.query(text)

   def query(self, text: str):
    text= normalize(text)
    embedding= self.embedder.encode(text)

    results= self.store.search(embedding)

    # cache is empty, so miss
    if not results:
        tokens = estimate_tokens(text)
        response = self.llm.generate(text)
        self.metrics.log_miss(tokens=tokens)
        self.store.add(embedding, text, response)
        return response

    top1_sim, top1_data = results[0]
    top2_sim = results[1][0] if len(results) > 1 else 0

  
    TTL = 3600
    # if cache entry is too old, then miss
    if time.time() - top1_data["timestamp"] > TTL:
        tokens = estimate_tokens(text)
        response = self.llm.generate(text)
        self.metrics.log_miss(tokens=tokens)
        self.store.add(embedding, text, response)
        return response

    overlap = keyword_overlap(text, top1_data["query"])
    if len(text.split()) > 10:
        if overlap < 0.1:
            tokens = estimate_tokens(text)
            response = self.llm.generate(text)
            self.metrics.log_miss(tokens=tokens)
            self.store.add(embedding, text, response)
            return response

    # hit
    if (self.policy.should_hit(top1_sim) and (top1_sim - top2_sim) > 0.02):
        tokens = estimate_tokens(text)
        self.metrics.log_hit(tokens=tokens)
        return top1_data["answer"]

    # miss
    tokens = estimate_tokens(text)
    response = self.llm.generate(text)
    self.metrics.log_miss(tokens=tokens)
    self.store.add(embedding, text, response)

    return response
