import logging
from typing import Dict

# Configure logging
logging.basicConfig(level=logging.INFO)


def score_relevance(response: str, query: str) -> float:
    """
    Scores the relevance of the response to the query.

    Args:
        response: The response string.
        query: The query string.

    Returns:
        A float representing the relevance score (0.0 to 1.0).
    """
    try:
        if not isinstance(response, str) or not isinstance(query, str):
            raise TypeError("Response and query must be strings.")

        # Simple heuristic: check for query words in response
        query_words = query.lower().split()
        response_words = response.lower().split()
        common_words = set(query_words) & set(response_words)
        relevance = len(common_words) / len(query_words) if query_words else 0.0
        return min(1.0, max(0.0, relevance))  # Ensure score is between 0 and 1
    except Exception as e:
        logging.error(f"Error scoring relevance: {e}")
        return 0.0


def score_coherence(response: str) -> float:
    """
    Scores the coherence of the response.

    Args:
        response: The response string.

    Returns:
        A float representing the coherence score (0.0 to 1.0).
    """
    try:
        if not isinstance(response, str):
            raise TypeError("Response must be a string.")

        # Simple heuristic: check for sentence length variation
        sentences = response.split(".")  # naive sentence splitting
        sentence_lengths = [len(s.split()) for s in sentences if s.strip()]

        if not sentence_lengths:
            return 0.0

        length_variation = max(sentence_lengths) - min(sentence_lengths)
        coherence = 1.0 / (length_variation + 1)  # higher variation = lower coherence
        return min(1.0, max(0.0, coherence))

    except Exception as e:
        logging.error(f"Error scoring coherence: {e}")
        return 0.0


def score_correctness(response: str, context: str) -> float:
    """
    Scores the correctness of the response given some context.

    Args:
        response: The response string.
        context: The context string.

    Returns:
        A float representing the correctness score (0.0 to 1.0).
    """
    try:
        if not isinstance(response, str) or not isinstance(context, str):
            raise TypeError("Response and context must be strings.")

        # Simple heuristic: check for context words in response
        context_words = context.lower().split()
        response_words = response.lower().split()
        common_words = set(context_words) & set(response_words)
        correctness = len(common_words) / len(context_words) if context_words else 0.0
        return min(1.0, max(0.0, correctness))
    except Exception as e:
        logging.error(f"Error scoring correctness: {e}")
        return 0.0


def evaluate_response(response: str, query: str, context: str) -> Dict[str, float]:
    """
    Evaluates the response based on relevance, coherence, and correctness.

    Args:
        response: The response string.
        query: The query string.
        context: The context string.

    Returns:
        A dictionary containing the scores for relevance, coherence, and correctness.
    """
    try:
        if not isinstance(response, str) or not isinstance(query, str) or not isinstance(context, str):
            raise TypeError("Response, query, and context must be strings.")

        relevance_score = score_relevance(response, query)
        coherence_score = score_coherence(response)
        correctness_score = score_correctness(response, context)

        return {
            "relevance": relevance_score,
            "coherence": coherence_score,
            "correctness": correctness_score,
        }
    except Exception as e:
        logging.error(f"Error evaluating response: {e}")
        return {
            "relevance": 0.0,
            "coherence": 0.0,
            "correctness": 0.0,
        }


if __name__ == "__main__":
    # Example usage
    query = "What is the capital of France?"
    response = "The capital of France is Paris."
    context = "France is a country in Europe. Its capital is Paris."

    evaluation = evaluate_response(response, query, context)
    print(f"Response Evaluation: {evaluation}")

    # Example with invalid input
    evaluation = evaluate_response(123, query, context)
    print(f"Response Evaluation with invalid input: {evaluation}")