#!/usr/bin/env python3
"""
EspoCRM API Client
Provides a clean interface to the EspoCRM REST API
"""

import requests
import json
from typing import Dict, List, Optional, Any
from urllib.parse import urljoin


class EspoCRMAPIClient:
    """Client for EspoCRM REST API"""
    
    def __init__(self, base_url: str, api_key: str, username: str):
        """
        Initialize API client
        
        Args:
            base_url: Base URL of EspoCRM (e.g., 'https://crm.bitbylaw.com')
            api_key: API authentication token
            username: Username for API access
        """
        self.base_url = base_url.rstrip('/')
        self.api_key = api_key
        self.username = username
        self.session = requests.Session()
        self.session.headers.update({
            'X-Api-Key': api_key,
            'Content-Type': 'application/json'
        })
        
    def _make_request(self, method: str, endpoint: str, data: Optional[Dict] = None, 
                     params: Optional[Dict] = None) -> Dict:
        """
        Make HTTP request to API
        
        Args:
            method: HTTP method (GET, POST, PUT, DELETE)
            endpoint: API endpoint (e.g., 'Contact')
            data: Request body data
            params: URL query parameters
            
        Returns:
            Response data as dict
            
        Raises:
            requests.HTTPError: If request fails
        """
        url = urljoin(f"{self.base_url}/api/v1/", endpoint)
        
        try:
            response = self.session.request(
                method=method,
                url=url,
                json=data,
                params=params
            )
            response.raise_for_status()
            
            if response.status_code == 204:  # No content
                return {}
            
            return response.json() if response.content else {}
            
        except requests.exceptions.HTTPError as e:
            print(f"❌ API Error: {method} {url}")
            print(f"   Status: {e.response.status_code}")
            if e.response.content:
                try:
                    error_data = e.response.json()
                    print(f"   Error: {json.dumps(error_data, indent=2)}")
                except:
                    print(f"   Response: {e.response.text}")
            raise
    
    # ============================================================================
    # CRUD Operations
    # ============================================================================
    
    def create(self, entity_type: str, data: Dict) -> Dict:
        """
        Create a new record
        
        Args:
            entity_type: Entity type (e.g., 'Contact', 'CMietobjekt')
            data: Record data
            
        Returns:
            Created record with ID
        """
        return self._make_request('POST', entity_type, data=data)
    
    def read(self, entity_type: str, record_id: str) -> Dict:
        """
        Read a record by ID
        
        Args:
            entity_type: Entity type
            record_id: Record ID
            
        Returns:
            Record data
        """
        return self._make_request('GET', f"{entity_type}/{record_id}")
    
    def update(self, entity_type: str, record_id: str, data: Dict) -> Dict:
        """
        Update a record
        
        Args:
            entity_type: Entity type
            record_id: Record ID
            data: Updated fields
            
        Returns:
            Updated record
        """
        return self._make_request('PUT', f"{entity_type}/{record_id}", data=data)
    
    def delete(self, entity_type: str, record_id: str) -> Dict:
        """
        Delete a record
        
        Args:
            entity_type: Entity type
            record_id: Record ID
            
        Returns:
            Empty dict on success
        """
        return self._make_request('DELETE', f"{entity_type}/{record_id}")
    
    def list(self, entity_type: str, params: Optional[Dict] = None) -> List[Dict]:
        """
        List records
        
        Args:
            entity_type: Entity type
            params: Query parameters (offset, maxSize, where, etc.)
            
        Returns:
            List of records
        """
        response = self._make_request('GET', entity_type, params=params)
        return response.get('list', [])
    
    # ============================================================================
    # Relationship Operations
    # ============================================================================
    
    def link(self, entity_type: str, record_id: str, link_name: str, 
             foreign_id: str) -> Dict:
        """
        Link two records
        
        Args:
            entity_type: Source entity type
            record_id: Source record ID
            link_name: Relationship name
            foreign_id: Target record ID
            
        Returns:
            Empty dict on success
        """
        endpoint = f"{entity_type}/{record_id}/{link_name}/{foreign_id}"
        return self._make_request('POST', endpoint)
    
    def unlink(self, entity_type: str, record_id: str, link_name: str, 
               foreign_id: str) -> Dict:
        """
        Unlink two records
        
        Args:
            entity_type: Source entity type
            record_id: Source record ID
            link_name: Relationship name
            foreign_id: Target record ID
            
        Returns:
            Empty dict on success
        """
        endpoint = f"{entity_type}/{record_id}/{link_name}/{foreign_id}"
        return self._make_request('DELETE', endpoint)
    
    def get_linked(self, entity_type: str, record_id: str, link_name: str) -> List[Dict]:
        """
        Get linked records
        
        Args:
            entity_type: Source entity type
            record_id: Source record ID
            link_name: Relationship name
            
        Returns:
            List of linked records
        """
        endpoint = f"{entity_type}/{record_id}/{link_name}"
        response = self._make_request('GET', endpoint)
        return response.get('list', [])
    
    # ============================================================================
    # Utility Methods
    # ============================================================================
    
    def check_connection(self) -> bool:
        """
        Test API connection
        
        Returns:
            True if connection successful
        """
        try:
            # Try to get current user info
            self._make_request('GET', 'User')
            return True
        except Exception as e:
            print(f"❌ Connection failed: {e}")
            return False
