import warnings
from ...domain.models.metric_type import EvaluationParams, MetricType, MetricTypeBase
from ...utils.string import build_query_params, is_valid_id
from ...infrastructure.clients.http_client import Client
from typing import List, Optional

class MetricTypeService:

    def __init__(self, client: Client):
        self._client = client

    def create(
        self,
        name: str,
        evaluation_params: Optional[List[str]] = None,
        criteria: Optional[str] = None,
        evaluation_steps: Optional[List[str]] = None,
    ):
        """
        Create a new metric type.
        
        Args:
            name (str): Name of the metric type.
            evaluation_params (list[str]): parameters that will be used for defining the criteria or evaluation_steps for the evaluation steps.
                
                For more information, refer to the documentation: https://docs.galtea.ai/concepts/metric-type
                
                Possible values are:
                - 'input': [Always required] The prompt or query sent to the model.
                - 'actual output': The actual output generated by the model.
                - 'expected output': The ideal answer for the given input.
                - 'context': Additional background information provided to the model.
                - 'retrieval context': The context retrieved by your RAG before sending the user query to your LLM.
            criteria (str, optional): Criteria for the metric type.
            evaluation_steps (list[str], optional): Evaluation steps for the metric type.
                
            
        Returns:
            Metric: The created metric type object.
        """
        try:
            # Validate that all evaluation_params exist in EvaluationParams enum and convert to camel case
            camel_case_evaluation_params=[]
            if evaluation_params:
                allowed_evaluation_params = [e.value for e in EvaluationParams]
                for param in evaluation_params:
                    lower_case_param = param.lower()
                    if lower_case_param not in allowed_evaluation_params:
                        raise ValueError(f"Invalid evaluation parameter: {param}. Must be one of {[e.value for e in EvaluationParams]}")
                    else:
                        camel_case_evaluation_params.append(lower_case_param[0] + ''.join(x for x in lower_case_param.title() if not x.isspace())[1:])

            metric_type = MetricTypeBase(
                name=name,
                criteria=criteria,
                evaluation_steps=evaluation_steps,
                evaluation_params=camel_case_evaluation_params,
            )

            metric_type.model_validate(metric_type.model_dump())
            response = self._client.post(f"metricTypes", json=metric_type.model_dump(by_alias=True))
            metric_type_response = MetricType(**response.json())
            return metric_type_response
        except Exception as e:
            print(f"Error creating Metric Type: {e}")
            return None

    def get(self, metric_type_id: str):
        """
        Retrieve a metric type by its ID.
        
        Args:
            metric_type_id (str): ID of the metric type to retrieve.
            
        Returns:
            Metric: The retrieved metric type object.
        """
        if not is_valid_id(metric_type_id):
            raise ValueError("Metric type ID provided is not valid.")
        
        response = self._client.get(f"metricTypes/{metric_type_id}")
        return MetricType(**response.json())
    
    def get_by_name(self, name: str):
        """
        Retrieve a metric type by its name.
        
        Args:
            name (str): Name of the metric type to retrieve.
            
        Returns:
            Metric: The retrieved metric type object.
        """        
        query_params = build_query_params(names=[name])
        response = self._client.get(f"metricTypes?{query_params}")
        metricTypes = [MetricType(**metric_type) for metric_type in response.json()]
        
        if not metricTypes:
            raise ValueError(f"Metric type with name {name} does not exist.")

        return metricTypes[0]

    def delete(self, metric_type_id: str):
        """
        Delete a metric type by its ID.
        
        Args:
            metric_type_id (str): ID of the metric type to delete.
            
        Returns:
            Metric: Deleted metric type object.
        """
        if not is_valid_id(metric_type_id):
            raise ValueError("Metric type ID provided is not valid.")
        
        self._client.delete(f"metricTypes/{metric_type_id}")
    
    def list(self, offset: Optional[int] = None, limit: Optional[int] = None) -> List[MetricType]:
        """
        Get a list of metric types.
        
        Args:
            offset (int, optional): Offset for pagination.
            limit (int, optional): Limit for pagination.
            
        Returns:
            list[Metric]: List of metric types.
        """
        query_params = build_query_params(offset=offset, limit=limit)
        response = self._client.get(f"metricTypes?{query_params}")
        metric_types = [MetricType(**metric_type) for metric_type in response.json()]
        return metric_types
