"""ToolCenter Python SDK - Main Client"""

import requests
from typing import Dict, Any, Optional, List, Union
import json


class ToolCenterError(Exception):
    """Base exception for ToolCenter API errors"""
    pass


class AuthenticationError(ToolCenterError):
    """Raised when API key is invalid or missing"""
    pass


class RateLimitError(ToolCenterError):
    """Raised when rate limit is exceeded"""
    pass


class ToolCenter:
    """Official ToolCenter Python SDK Client
    
    A comprehensive API client for ToolCenter's web automation and utility services.
    Provides access to screenshot, PDF generation, QR codes, metadata extraction,
    and many other web-related tools.
    
    Args:
        api_key (str): Your ToolCenter API key
        base_url (str, optional): Custom base URL. Defaults to 'https://toolcenter.dev'
    
    Example:
        >>> from toolcenter import ToolCenter
        >>> tc = ToolCenter('your-api-key')
        >>> result = tc.screenshot(url='https://example.com', width=1920)
    """
    
    def __init__(self, api_key: str, base_url: str = "https://toolcenter.dev"):
        """Initialize ToolCenter client
        
        Args:
            api_key: Your ToolCenter API key
            base_url: Base URL for API requests (defaults to https://toolcenter.dev)
        """
        self.api_key = api_key
        self.base_url = base_url.rstrip('/')
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json',
            'User-Agent': 'ToolCenter-Python-SDK/1.1.0'
        })
    
    def _make_request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Make HTTP request to ToolCenter API
        
        Args:
            method: HTTP method (GET, POST)
            endpoint: API endpoint path
            data: Request payload data
            
        Returns:
            JSON response from API
            
        Raises:
            AuthenticationError: Invalid API key
            RateLimitError: Rate limit exceeded
            ToolCenterError: Other API errors
        """
        url = f"{self.base_url}{endpoint}"
        
        try:
            if method.upper() == 'GET':
                response = self.session.get(url, params=data)
            else:
                response = self.session.post(url, json=data)
            
            # Handle different error status codes
            if response.status_code == 401:
                raise AuthenticationError("Invalid API key")
            elif response.status_code == 429:
                raise RateLimitError("Rate limit exceeded")
            elif response.status_code >= 400:
                try:
                    error_data = response.json()
                    raise ToolCenterError(f"API error: {error_data.get('message', 'Unknown error')}")
                except ValueError:
                    raise ToolCenterError(f"HTTP {response.status_code}: {response.text}")
            
            return response.json()
            
        except requests.exceptions.RequestException as e:
            raise ToolCenterError(f"Request failed: {str(e)}")
    
    def _make_raw_request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None):
        """Make HTTP request for binary responses
        
        Args:
            method: HTTP method (GET, POST)
            endpoint: API endpoint path
            data: Request payload data
            
        Returns:
            Raw response object
            
        Raises:
            AuthenticationError: Invalid API key
            RateLimitError: Rate limit exceeded
            ToolCenterError: Other API errors
        """
        url = f"{self.base_url}{endpoint}"
        
        try:
            if method.upper() == 'GET':
                response = self.session.get(url, params=data)
            else:
                response = self.session.post(url, json=data)
            
            # Handle different error status codes
            if response.status_code == 401:
                raise AuthenticationError("Invalid API key")
            elif response.status_code == 429:
                raise RateLimitError("Rate limit exceeded")
            elif response.status_code >= 400:
                try:
                    error_data = response.json()
                    raise ToolCenterError(f"API error: {error_data.get('message', 'Unknown error')}")
                except ValueError:
                    raise ToolCenterError(f"HTTP {response.status_code}: {response.text}")
            
            return response
            
        except requests.exceptions.RequestException as e:
            raise ToolCenterError(f"Request failed: {str(e)}")
    
    def screenshot(self, **kwargs) -> Dict[str, Any]:
        """Capture webpage screenshots
        
        Args:
            url (str): Target URL to screenshot
            width (int, optional): Viewport width
            height (int, optional): Viewport height  
            format (str, optional): Output format (png, jpeg, webp)
            full_page (bool, optional): Capture full page
            device (str, optional): Device emulation
            wait_for (str, optional): Element selector to wait for
            delay (int, optional): Delay before capture in milliseconds
            
        Returns:
            Dict containing screenshot data and metadata
        """
        return self._make_request('POST', '/api/v1/screenshot', kwargs)
    
    def pdf(self, **kwargs) -> Dict[str, Any]:
        """Generate PDF from webpage
        
        Args:
            url (str): Target URL to convert to PDF
            format (str, optional): Page format (A4, Letter, etc.)
            landscape (bool, optional): Use landscape orientation
            margin (dict, optional): Page margins
            print_background (bool, optional): Include background graphics
            wait_for (str, optional): Element selector to wait for
            
        Returns:
            Dict containing PDF data and metadata
        """
        return self._make_request('POST', '/api/v1/pdf', kwargs)
    
    def qr(self, **kwargs) -> Dict[str, Any]:
        """Generate QR codes
        
        Args:
            data (str): Data to encode in QR code
            size (int, optional): QR code size in pixels
            format (str, optional): Output format (png, svg)
            error_correction (str, optional): Error correction level
            
        Returns:
            Dict containing QR code image and metadata
        """
        return self._make_request('POST', '/api/v1/qr', kwargs)
    
    def og_image(self, **kwargs) -> Dict[str, Any]:
        """Extract or generate Open Graph images
        
        Args:
            url (str): Target URL
            fallback (bool, optional): Generate fallback image if none found
            
        Returns:
            Dict containing Open Graph image data
        """
        return self._make_request('POST', '/api/v1/og-image', kwargs)
    
    def metadata(self, **kwargs) -> Dict[str, Any]:
        """Extract webpage metadata
        
        Args:
            url (str): Target URL to analyze
            include_og (bool, optional): Include Open Graph data
            include_twitter (bool, optional): Include Twitter Card data
            include_schema (bool, optional): Include Schema.org data
            
        Returns:
            Dict containing extracted metadata
        """
        return self._make_request('POST', '/api/v1/metadata', kwargs)
    
    def watermark(self, **kwargs) -> Dict[str, Any]:
        """Add watermarks to images
        
        Args:
            image_url (str): Source image URL
            watermark_text (str, optional): Text watermark
            watermark_image (str, optional): Image watermark URL
            position (str, optional): Watermark position
            opacity (float, optional): Watermark opacity (0.0-1.0)
            
        Returns:
            Dict containing watermarked image data
        """
        return self._make_request('POST', '/api/v1/watermark', kwargs)
    
    def compress(self, **kwargs) -> Dict[str, Any]:
        """Compress and optimize images
        
        Args:
            image_url (str): Source image URL
            quality (int, optional): Compression quality (1-100)
            format (str, optional): Output format
            max_width (int, optional): Maximum width
            max_height (int, optional): Maximum height
            
        Returns:
            Dict containing compressed image data
        """
        return self._make_request('POST', '/api/v1/compress', kwargs)
    
    def html_to_image(self, **kwargs) -> Dict[str, Any]:
        """Convert HTML content to image
        
        Args:
            html (str): HTML content to render
            css (str, optional): Additional CSS styles
            width (int, optional): Render width
            height (int, optional): Render height
            format (str, optional): Output format
            
        Returns:
            Dict containing rendered image data
        """
        return self._make_request('POST', '/api/v1/html-to-image', kwargs)
    
    def favicon(self, **kwargs) -> Dict[str, Any]:
        """Extract website favicons
        
        Args:
            url (str): Target website URL
            size (int, optional): Preferred favicon size
            format (str, optional): Output format
            
        Returns:
            Dict containing favicon data and alternatives
        """
        return self._make_request('POST', '/api/v1/favicon', kwargs)
    
    def dns(self, **kwargs) -> Dict[str, Any]:
        """Perform DNS lookups
        
        Args:
            domain (str): Domain to lookup
            record_type (str, optional): DNS record type (A, AAAA, MX, etc.)
            
        Returns:
            Dict containing DNS records and information
        """
        return self._make_request('POST', '/api/v1/dns', kwargs)
    
    def ssl(self, **kwargs) -> Dict[str, Any]:
        """Check SSL certificate information
        
        Args:
            domain (str): Domain to check
            port (int, optional): Port number (defaults to 443)
            
        Returns:
            Dict containing SSL certificate details
        """
        return self._make_request('POST', '/api/v1/ssl', kwargs)
    
    def status(self, **kwargs) -> Dict[str, Any]:
        """Check website status and response information
        
        Args:
            url (str): URL to check
            follow_redirects (bool, optional): Follow redirects
            timeout (int, optional): Request timeout in seconds
            
        Returns:
            Dict containing status code, headers, and response details
        """
        return self._make_request('POST', '/api/v1/status', kwargs)
    
    def link_preview(self, **kwargs) -> Dict[str, Any]:
        """Generate rich link previews
        
        Args:
            url (str): URL to generate preview for
            include_screenshot (bool, optional): Include page screenshot
            
        Returns:
            Dict containing preview data with title, description, image
        """
        return self._make_request('POST', '/api/v1/link-preview', kwargs)
    
    def tech_stack(self, **kwargs) -> Dict[str, Any]:
        """Detect website technology stack
        
        Args:
            url (str): Website URL to analyze
            deep_scan (bool, optional): Perform deep analysis
            
        Returns:
            Dict containing detected technologies, frameworks, and services
        """
        return self._make_request('POST', '/api/v1/techstack', kwargs)
    
    def whois(self, **kwargs) -> Dict[str, Any]:
        """Perform WHOIS domain lookup
        
        Args:
            domain (str): Domain to lookup
            
        Returns:
            Dict containing WHOIS information
        """
        return self._make_request('POST', '/api/v1/whois', kwargs)
    
    def colors(self, **kwargs) -> Dict[str, Any]:
        """Extract dominant colors from images or websites
        
        Args:
            url (str, optional): Website URL
            image_url (str, optional): Image URL
            palette_size (int, optional): Number of colors to extract
            
        Returns:
            Dict containing color palette and analysis
        """
        return self._make_request('POST', '/api/v1/colors', kwargs)
    
    def placeholder(self, **kwargs) -> Dict[str, Any]:
        """Generate placeholder images
        
        Args:
            width (int): Image width
            height (int): Image height
            background_color (str, optional): Background color hex
            text_color (str, optional): Text color hex
            text (str, optional): Custom text
            format (str, optional): Output format
            
        Returns:
            Dict containing placeholder image data
        """
        return self._make_request('POST', '/api/v1/placeholder', kwargs)
    
    def shorten(self, **kwargs) -> Dict[str, Any]:
        """Shorten URL
        
        Args:
            url (str): URL to shorten
            
        Returns:
            Dict containing shortened URL data
        """
        return self._make_request('POST', '/api/v1/shorten', kwargs)
    
    def markdown(self, **kwargs) -> Dict[str, Any]:
        """Convert Markdown to HTML
        
        Args:
            markdown (str): Markdown content
            options (dict, optional): Conversion options
            
        Returns:
            Dict containing HTML conversion data
        """
        return self._make_request('POST', '/api/v1/markdown', kwargs)
    
    def minify(self, **kwargs) -> Dict[str, Any]:
        """Minify content (CSS, JS, HTML)
        
        Args:
            content (str): Content to minify
            type (str): Content type (css, js, html)
            
        Returns:
            Dict containing minified content data
        """
        return self._make_request('POST', '/api/v1/minify', kwargs)
    
    def base64(self, **kwargs) -> Dict[str, Any]:
        """Base64 encode/decode
        
        Args:
            action (str): Action (encode/decode)
            content (str): Content to process
            url (str, optional): URL to encode
            
        Returns:
            Dict containing base64 processing result
        """
        return self._make_request('POST', '/api/v1/base64', kwargs)
    
    def hash(self, **kwargs) -> Dict[str, Any]:
        """Generate hash of content
        
        Args:
            content (str): Content to hash
            algorithms (list, optional): Hash algorithms to use
            
        Returns:
            Dict containing hash results
        """
        return self._make_request('POST', '/api/v1/hash', kwargs)
    
    def json(self, **kwargs) -> Dict[str, Any]:
        """JSON formatter and validator
        
        Args:
            content (str): JSON content
            action (str, optional): Action (format, minify, validate)
            
        Returns:
            Dict containing JSON processing result
        """
        return self._make_request('POST', '/api/v1/json', kwargs)
    
    def cron(self, **kwargs) -> Dict[str, Any]:
        """Parse cron expression
        
        Args:
            expression (str): Cron expression
            num_next (int, optional): Number of next occurrences
            
        Returns:
            Dict containing cron parsing result
        """
        return self._make_request('POST', '/api/v1/cron', kwargs)
    
    def email_validate(self, **kwargs) -> Dict[str, Any]:
        """Validate email address
        
        Args:
            email (str): Email to validate
            
        Returns:
            Dict containing email validation result
        """
        return self._make_request('POST', '/api/v1/email-validate', kwargs)
    
    def geoip(self, **kwargs) -> Dict[str, Any]:
        """Get IP geolocation information
        
        Args:
            ip (str, optional): IP address (uses request IP if not provided)
            
        Returns:
            Dict containing IP geolocation data
        """
        return self._make_request('GET', '/api/v1/geoip', kwargs)
    
    def user_agent(self, **kwargs) -> Dict[str, Any]:
        """Parse user agent string
        
        Args:
            user_agent (str, optional): User agent string (uses request UA if not provided)
            
        Returns:
            Dict containing user agent parsing result
        """
        return self._make_request('GET', '/api/v1/user-agent', kwargs)
    
    def scrape(self, **kwargs) -> Dict[str, Any]:
        """Scrape website content
        
        Args:
            url (str): URL to scrape
            selector (str, optional): CSS selector to extract
            format (str, optional): Output format (text, html)
            wait_for (str, optional): Element to wait for
            
        Returns:
            Dict containing scraped content data
        """
        return self._make_request('POST', '/api/v1/scrape', kwargs)
    
    def pagespeed(self, **kwargs) -> Dict[str, Any]:
        """Analyze page speed
        
        Args:
            url (str): URL to analyze
            
        Returns:
            Dict containing page speed analysis result
        """
        return self._make_request('POST', '/api/v1/pagespeed', kwargs)
    
    def responsive(self, **kwargs) -> Dict[str, Any]:
        """Test responsive design
        
        Args:
            url (str): URL to test
            devices (list, optional): Device types to test
            
        Returns:
            Dict containing responsive design analysis
        """
        return self._make_request('POST', '/api/v1/responsive', kwargs)
    
    def broken_links(self, **kwargs) -> Dict[str, Any]:
        """Check for broken links
        
        Args:
            url (str): URL to check
            max_links (int, optional): Maximum links to check
            
        Returns:
            Dict containing broken links report
        """
        return self._make_request('POST', '/api/v1/broken-links', kwargs)
    
    def accessibility(self, **kwargs) -> Dict[str, Any]:
        """Test accessibility
        
        Args:
            url (str): URL to test
            standard (str, optional): Accessibility standard (WCAG21A, WCAG21AA, WCAG21AAA)
            
        Returns:
            Dict containing accessibility test results
        """
        return self._make_request('POST', '/api/v1/accessibility', kwargs)
    
    def seo(self, **kwargs) -> Dict[str, Any]:
        """SEO analysis
        
        Args:
            url (str): URL to analyze
            
        Returns:
            Dict containing SEO analysis results
        """
        return self._make_request('POST', '/api/v1/seo', kwargs)
    
    def barcode(self, **kwargs) -> Union[bytes, Dict[str, Any]]:
        """Generate barcode
        
        Args:
            data (str): Data to encode
            type (str, optional): Barcode type (code128, qr, etc.)
            width (int, optional): Barcode width
            height (int, optional): Barcode height
            format (str, optional): Output format (png, svg)
            
        Returns:
            Binary barcode image data
        """
        # For barcode, return raw response for binary data
        response = self._make_raw_request('POST', '/api/v1/barcode', kwargs)
        return response.content
    
    def image_resize(self, **kwargs) -> Union[bytes, Dict[str, Any]]:
        """Resize image
        
        Args:
            url (str): Image URL
            width (int, optional): Target width
            height (int, optional): Target height
            fit (str, optional): Fit mode (cover, contain, fill)
            format (str, optional): Output format (png, jpeg, webp)
            quality (int, optional): Output quality (1-100)
            
        Returns:
            Binary resized image data
        """
        # For image resize, return raw response for binary data
        response = self._make_raw_request('POST', '/api/v1/image-resize', kwargs)
        return response.content
    
    def carbon(self, **kwargs) -> Dict[str, Any]:
        """Generate Carbon code image
        
        Args:
            url (str): URL of code to capture
            
        Returns:
            Dict containing Carbon code image data
        """
        return self._make_request('POST', '/api/v1/carbon', kwargs)
    
    def diff(self, **kwargs) -> Dict[str, Any]:
        """Compare two URLs (diff)
        
        Args:
            url1 (str): First URL to compare
            url2 (str): Second URL to compare
            
        Returns:
            Dict containing diff comparison results
        """
        return self._make_request('POST', '/api/v1/diff', kwargs)

    def usage(self) -> Dict[str, Any]:
        """Get API usage statistics
        
        Returns:
            Dict containing usage data, limits, and billing information
        """
        return self._make_request('GET', '/api/v1/usage')
    
    def bulk_screenshot(self, urls: List[str], **kwargs) -> Dict[str, Any]:
        """Capture screenshots of multiple URLs
        
        Args:
            urls: List of URLs to screenshot
            **kwargs: Additional screenshot parameters applied to all URLs
            
        Returns:
            Dict containing results for each URL
        """
        data = {'urls': urls, **kwargs}
        return self._make_request('POST', '/api/v1/bulk/screenshot', data)
    
    def bulk_pdf(self, urls: List[str], **kwargs) -> Dict[str, Any]:
        """Generate PDFs for multiple URLs
        
        Args:
            urls: List of URLs to convert to PDF
            **kwargs: Additional PDF parameters applied to all URLs
            
        Returns:
            Dict containing results for each URL
        """
        data = {'urls': urls, **kwargs}
        return self._make_request('POST', '/api/v1/bulk/pdf', data)
    
    def bulk_metadata(self, urls: List[str], **kwargs) -> Dict[str, Any]:
        """Extract metadata from multiple URLs
        
        Args:
            urls: List of URLs to analyze
            **kwargs: Additional metadata parameters applied to all URLs
            
        Returns:
            Dict containing metadata for each URL
        """
        data = {'urls': urls, **kwargs}
        return self._make_request('POST', '/api/v1/bulk/metadata', data)