"""
API client for CZBG Lambda API.

Makes HTTP requests to the Lambda endpoint for job submission and status.
Follows CLAUDE.md: Single responsibility, <10 methods, <50 lines/method.
"""

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

from .config import APIConfig
from .auth import AWSRequestSigner


class APIClient:
    """
    HTTP client for CZBG Lambda API with IAM authentication.

    Single responsibility: Make HTTP requests to API.
    Dependencies injected: API configuration, AWS request signer.
    """

    def __init__(self, config: APIConfig, signer: AWSRequestSigner):
        """
        Initialize API client with IAM authentication.

        Args:
            config: API configuration
            signer: AWS request signer (required for IAM auth)
        """
        self.config = config
        self.signer = signer
        self.session = requests.Session()

        # Set default timeout
        self.session.request = self._add_timeout(self.session.request)

    def submit_job(
        self,
        job_type: str,
        config_s3_path: Optional[str] = None,
        config_content: Optional[str] = None,
        config_type: str = "file",
        dataset_name: Optional[str] = None,
        description: Optional[str] = None,
        user_id: str = "cli-user",
        **kwargs,
    ) -> str:
        """
        Submit job to API.

        Args:
            job_type: Job type (generate, k8s, metadata, usage, discount, upload)
            config_s3_path: S3 path to config file or directory (optional)
            config_content: Inline config content (optional)
            config_type: 'file' or 'directory'
            dataset_name: Optional dataset name
            description: Optional job description
            user_id: User identifier (default: cli-user)
            **kwargs: Additional job parameters

        Returns:
            Job ID

        Raises:
            requests.HTTPError: If request fails
        """
        endpoint = f"{self.config.api_url}/api/v1/jobs/{job_type}"

        # Build payload with all required fields
        payload = {
            "job_type": job_type,
            "dataset_name": dataset_name or f"{job_type}-dataset",
            "user_id": user_id,
            "description": description or f"{job_type} job",
            "config_type": config_type,
        }

        # Add config (either inline or S3 path)
        if config_content:
            payload["config_content"] = config_content
        elif config_s3_path:
            payload["config_s3_path"] = config_s3_path

        # Add any additional kwargs
        payload.update(kwargs)

        # Make request (with signing if IAM auth is enabled)
        response = self._make_signed_request("POST", endpoint, json=payload)

        # Check for errors and include response body in error message
        if not response.ok:
            error_detail = response.text
            try:
                error_json = response.json()
                error_detail = error_json.get("detail", response.text)
            except:
                pass
            response.raise_for_status()  # Will raise with status code

        result = response.json()
        return result["job_id"]

    def get_job_status(self, job_id: str) -> Dict[str, Any]:
        """
        Get job status from API.

        Args:
            job_id: Job ID to query

        Returns:
            Job status dictionary

        Raises:
            requests.HTTPError: If request fails
        """
        endpoint = f"{self.config.api_url}/api/v1/jobs/{job_id}/status"

        # Make request (with signing if IAM auth is enabled)
        response = self._make_signed_request("GET", endpoint)
        response.raise_for_status()

        return response.json()

    def _make_signed_request(
        self,
        method: str,
        url: str,
        **kwargs
    ) -> requests.Response:
        """
        Make HTTP request with AWS SigV4 signing.

        Args:
            method: HTTP method (GET, POST, etc.)
            url: Request URL
            **kwargs: Additional arguments for requests (json, params, etc.)

        Returns:
            Response object
        """
        # Prepare request data for signing
        body = None
        headers = {}

        # Handle JSON payload
        if "json" in kwargs:
            body = json.dumps(kwargs["json"])
            headers["Content-Type"] = "application/json"

        # Sign the request with AWS SigV4 (only sign explicitly set headers)
        signed_headers = self.signer.sign_request(method, url, headers, body)

        # Make request with signed headers
        # Use plain requests (not session) to avoid additional headers being added
        response = requests.request(
            method,
            url,
            headers=signed_headers,
            data=body,
            timeout=self.config.timeout
        )
        return response

    def _add_timeout(self, request_method):
        """Add default timeout to requests."""

        def wrapper(*args, **kwargs):
            if "timeout" not in kwargs:
                kwargs["timeout"] = self.config.timeout
            return request_method(*args, **kwargs)

        return wrapper
