"""Record operations for Archer REST API with Pydantic model support."""

import logging
from typing import Dict, List, Optional, Any, Union

from ..exceptions import ResourceNotFoundError, ValidationError, ArcherAPIException
from ..models import (
    RecordCreateRequest,
    RecordUpdateRequest,
    RecordResponse,
    RecordContent,
    FieldContent
)
from .base import BaseAPI


logger = logging.getLogger(__name__)


class RecordsAPI(BaseAPI):
    """API client for Archer record operations."""
    
    def get(self, content_id: int, as_model: bool = False) -> Union[Dict[str, Any], RecordContent]:
        """
        Get a specific record by content ID.
        
        Args:
            content_id: The content ID of the record
            as_model: If True, return as RecordContent model, otherwise dict
            
        Returns:
            Record data as dictionary or RecordContent model
            
        Example:
            >>> # As dictionary (backward compatible)
            >>> record_dict = client.rest.records.get(123)
            
            >>> # As Pydantic model (with validation)
            >>> record_model = client.rest.records.get(123, as_model=True)
            >>> print(record_model.LevelId)
            >>> print(record_model.FieldContents)
        """
        url = f"{self.base_url}/api/core/content/{content_id}"
        
        try:
            response = self._make_request("GET", url)
            data = response.json()
            
            if as_model:
                # Parse and validate as Pydantic model
                return RecordContent(**data)
            return data
            
        except ArcherAPIException as e:
            if "404" in str(e):
                raise ResourceNotFoundError(f"Record {content_id} not found")
            raise
    
    def create(
        self,
        application_id: int = None,
        field_values: Dict[str, Any] = None,
        sub_form_data: Optional[List[Dict]] = None,
        request_model: Optional[RecordCreateRequest] = None
    ) -> int:
        """
        Create a new record in an application.
        
        You can use either the traditional parameters OR a RecordCreateRequest model.
        
        Args:
            application_id: ID of the application (traditional way)
            field_values: Dictionary mapping field names to values (traditional way)
            sub_form_data: Optional list of sub-form records (traditional way)
            request_model: RecordCreateRequest model (model-based way)
            
        Returns:
            Content ID of the created record
            
        Example (Traditional):
            >>> record_id = client.rest.records.create(
            ...     application_id=75,
            ...     field_values={
            ...         "Title": "New Incident",
            ...         "Priority": 1,
            ...         "Status": "Open"
            ...     }
            ... )
        
        Example (Model-based):
            >>> from py_ullr.models import RecordCreateRequest
            >>> 
            >>> request = RecordCreateRequest.from_fields(
            ...     application_id=75,
            ...     field_values={
            ...         "Title": "New Incident",
            ...         "Priority": 1,
            ...         "Status": "Open"
            ...     }
            ... )
            >>> record_id = client.rest.records.create(request_model=request)
        """
        url = f"{self.base_url}/api/core/content"
        
        # Use model if provided, otherwise build from parameters
        if request_model:
            payload = request_model.model_dump(exclude_none=True)
        else:
            if not application_id or not field_values:
                raise ValueError("Either request_model or (application_id and field_values) must be provided")
            
            # Build field content (traditional way)
            field_contents = {}
            for field_name, value in field_values.items():
                field_contents[field_name] = {
                    "Type": self._infer_field_type(value),
                    "Value": value
                }
            
            payload = {
                "Content": {
                    "LevelId": application_id,
                    "FieldContents": field_contents
                }
            }
            
            if sub_form_data:
                payload["Content"]["SubformData"] = sub_form_data
        
        try:
            response = self._make_request("POST", url, json=payload)
            data = response.json()
            
            # Optionally parse response as model
            response_model = RecordResponse(**data)
            
            if not response_model.IsSuccessful:
                raise ValidationError(f"Record creation failed: {response_model.ValidationMessages}")
            
            return response_model.record_id
            
        except ArcherAPIException as e:
            if "validation" in str(e).lower():
                raise ValidationError(f"Invalid field values: {e}")
            raise
    
    def update(
        self,
        content_id: int = None,
        field_values: Dict[str, Any] = None,
        request_model: Optional[RecordUpdateRequest] = None
    ) -> bool:
        """
        Update an existing record.
        
        Args:
            content_id: Content ID of the record to update (traditional way)
            field_values: Dictionary of field names and new values (traditional way)
            request_model: RecordUpdateRequest model (model-based way)
            
        Returns:
            True if update successful
            
        Example (Traditional):
            >>> success = client.rest.records.update(
            ...     content_id=123,
            ...     field_values={"Status": "Closed"}
            ... )
        
        Example (Model-based):
            >>> from py_ullr.models import RecordUpdateRequest, RecordContent, FieldContent
            >>> 
            >>> # First, get the existing record
            >>> existing = client.rest.records.get(123, as_model=True)
            >>> 
            >>> # Update specific fields
            >>> existing.FieldContents["Status"] = FieldContent(Type=1, Value="Closed")
            >>> 
            >>> request = RecordUpdateRequest(Content=existing)
            >>> success = client.rest.records.update(request_model=request)
        """
        url = f"{self.base_url}/api/core/content/{content_id or request_model.Content.Id}"
        
        if request_model:
            payload = request_model.model_dump(exclude_none=True)
        else:
            if not content_id or not field_values:
                raise ValueError("Either request_model or (content_id and field_values) must be provided")
            
            field_contents = {}
            for field_name, value in field_values.items():
                field_contents[field_name] = {
                    "Type": self._infer_field_type(value),
                    "Value": value
                }
            
            payload = {
                "Content": {
                    "Id": content_id,
                    "FieldContents": field_contents
                }
            }
        
        response = self._make_request("PUT", url, json=payload)
        return response.status_code == 200
    
    def delete(self, content_id: int) -> bool:
        """Delete a record."""
        url = f"{self.base_url}/api/core/content/{content_id}"
        response = self._make_request("DELETE", url)
        return response.status_code == 200
    
    def search(
        self,
        application_id: int,
        filters: Optional[Dict[str, Any]] = None,
        max_results: int = 100
    ) -> List[Dict[str, Any]]:
        """
        Search for records in an application (deprecated - use filter_by_reference).
        
        Note: This method uses a placeholder endpoint that may not exist in all Archer versions.
        """
        logger.warning("records.search() may not be supported. Consider using filter_by_reference() instead.")
        url = f"{self.base_url}/api/core/content/search"
        
        payload = {
            "LevelId": application_id,
            "MaxResultCount": max_results
        }
        
        if filters:
            payload["Filters"] = filters
        
        response = self._make_request("POST", url, json=payload)
        data = response.json()
        return data.get("RequestedObject", {}).get("Records", [])
    
    @staticmethod
    def _infer_field_type(value: Any) -> int:
        """Infer Archer field type from Python value."""
        if isinstance(value, str):
            return 1  # Text
        elif isinstance(value, (int, float)):
            return 2  # Numeric
        elif isinstance(value, bool):
            return 3  # Boolean
        elif isinstance(value, list):
            return 4  # Values List
        else:
            return 1  # Default to text
