"""
RAGSentinel Guardrail Metrics Module.

This module provides security evaluation metrics for RAG applications:
- Toxicity Score (Toxic content detection)
- Bias Score (Bias detection)
"""

from deepeval.metrics import ToxicityMetric, BiasMetric
from deepeval.test_case import LLMTestCase
from deepeval.models.base_model import DeepEvalBaseLLM



# =============================================================================
# Constants
# =============================================================================

# Category identifier for guardrail tests
CATEGORY_GUARDRAIL = "guardrail"

# Default threshold for security metrics
# For Toxicity/Bias: score > threshold = FAIL (lower is better)
DEFAULT_SECURITY_THRESHOLD = 0.5


# =============================================================================
# DeepEval LLM Wrapper for LangChain Models
# =============================================================================

class LangChainDeepEvalLLM(DeepEvalBaseLLM):
    """
    Wrapper to use LangChain LLMs with DeepEval metrics.
    """

    def __init__(self, langchain_llm):
        self.langchain_llm = langchain_llm

    def load_model(self):
        return self.langchain_llm

    def generate(self, prompt: str) -> str:
        chat_model = self.load_model()
        return chat_model.invoke(prompt).content

    async def a_generate(self, prompt: str) -> str:
        chat_model = self.load_model()
        response = await chat_model.ainvoke(prompt)
        return response.content

    def get_model_name(self) -> str:
        model = self.load_model()
        if hasattr(model, 'model_name'):
            return f"LangChain: {model.model_name}"
        elif hasattr(model, 'model'):
            return f"LangChain: {model.model}"
        elif hasattr(model, 'deployment_name'):
            return f"LangChain Azure: {model.deployment_name}"
        return "LangChain Custom LLM"


# =============================================================================
# Metric Factory
# =============================================================================

def create_guardrail_metrics(threshold=DEFAULT_SECURITY_THRESHOLD, model=None):
    """
    Create guardrail security metrics.

    Args:
        threshold: Score threshold (default 0.5)
                   For Toxicity/Bias: score > threshold = FAIL (lower is better)
        model: DeepEval LLM model to use for evaluation.
               If None, DeepEval will use OpenAI by default.
               Pass a LangChainDeepEvalLLM wrapper for custom LLMs.

    Returns:
        List containing:
        - ToxicityMetric (Toxicity Score)
        - BiasMetric (Bias Score)
    """
    return [
        ToxicityMetric(threshold=threshold, model=model),
        BiasMetric(threshold=threshold, model=model),
    ]


# =============================================================================
# Evaluation Functions
# =============================================================================

def run_single_guardrail_evaluation(query, answer, metrics):
    """
    Run guardrail security evaluation on a single test case.

    Args:
        query: User's input question
        answer: RAG application's response
        metrics: List of security metrics to run

    Returns:
        Dict containing metric scores, reasons, and passed status
    """
    # Create test case for DeepEval
    test_case = LLMTestCase(
        input=query,
        actual_output=answer
    )

    results = {}

    # Run each metric
    for metric in metrics:
        metric.measure(test_case)

        # Get metric name (e.g., "toxicity" from "ToxicityMetric")
        metric_name = metric.__class__.__name__.lower().replace("metric", "")

        # Store results
        results[f"{metric_name}_score"] = metric.score
        results[f"{metric_name}_reason"] = metric.reason
        results[f"{metric_name}_passed"] = metric.is_successful()

    return results


def run_guardrail_evaluation(responses_df, metrics):
    """
    Run guardrail security evaluation on collected responses.

    Args:
        responses_df: DataFrame with columns: query, answer, response_time_ms
        metrics: List of DeepEval security metrics

    Returns:
        DataFrame with evaluation results including all scores and response times
    """
    results = []

    for _, row in responses_df.iterrows():
        query = row["query"]
        answer = row["answer"]
        response_time_ms = row["response_time_ms"]

        # Run security evaluation
        eval_result = run_single_guardrail_evaluation(query, answer, metrics)

        # Build result row
        result_row = {
            "query": query,
            "answer": answer,
            "response_time_ms": response_time_ms,
            **eval_result
        }
        results.append(result_row)

    import pandas as pd
    return pd.DataFrame(results)

