"""
Execution router for API vs local mode.

Routes command execution between API (Lambda + ECS) and local execution.
Follows CLAUDE.md: Single responsibility, <10 methods, <50 lines/method.
"""

from pathlib import Path
from typing import Dict, Any, Optional
from rich.console import Console

from .client import APIClient
from .auth import AWSRequestSigner
from .poller import JobPoller, JobFailedException
from .progress import ProgressDisplay
from .config import ConfigService
from .s3_uploader import S3ConfigUploader


class ExecutionRouter:
    """
    Route execution between API and local modes.

    Single responsibility: Execution mode routing.
    Dependencies injected: Console for progress display.
    """

    def __init__(self, console: Console):
        """
        Initialize execution router.

        Args:
            console: Rich console for output
        """
        self.console = console
        self.config_service = ConfigService()
        self.progress_display = ProgressDisplay(console)

    def execute_api(
        self,
        job_type: str,
        config_path: Path,
        dataset_name: Optional[str] = None,
        description: Optional[str] = None,
        **kwargs,
    ) -> Dict[str, Any]:
        """
        Execute via API (Lambda + ECS).

        Args:
            job_type: Job type (generate, k8s, metadata, etc.)
            config_path: Path to config file or directory
            dataset_name: Optional dataset name
            description: Optional job description
            **kwargs: Additional job parameters

        Returns:
            Job result dictionary

        Raises:
            ValueError: If API configuration invalid
            RuntimeError: If job execution fails
        """
        # Validate API configuration
        api_config = self.config_service.get_api_config()
        self.config_service.validate_api_config(api_config)

        # Prepare config for submission
        config_data = self._prepare_config(config_path, job_type)

        # Submit job to API
        api_client = self._create_api_client(api_config)
        job_id = self._submit_job(
            api_client, job_type, config_data,
            dataset_name, description, **kwargs
        )

        # Monitor job until completion
        return self._monitor_job(api_client, job_id, job_type)

    def _prepare_config(
        self, config_path: Path, job_type: str
    ) -> Dict[str, Any]:
        """
        Prepare config for API submission.

        Args:
            config_path: Path to config file or directory
            job_type: Job type for S3 upload path

        Returns:
            Dictionary with config_content, config_type, config_s3_path
        """
        if config_path.is_file():
            return {
                "config_content": config_path.read_text(),
                "config_type": "file",
                "config_s3_path": None
            }

        # Directory config - pre-upload to S3
        import uuid
        job_id = str(uuid.uuid4())
        s3_uploader = S3ConfigUploader()
        config_s3_path = s3_uploader.upload_config(
            config_path, job_type, job_id
        )

        return {
            "config_content": None,
            "config_type": "directory",
            "config_s3_path": config_s3_path
        }

    def _create_api_client(self, api_config) -> APIClient:
        """Create authenticated API client."""
        signer = AWSRequestSigner()
        return APIClient(api_config, signer)

    def _submit_job(
        self,
        api_client: APIClient,
        job_type: str,
        config_data: Dict[str, Any],
        dataset_name: Optional[str],
        description: Optional[str],
        **kwargs
    ) -> str:
        """
        Submit job to API.

        Returns:
            Job ID
        """
        job_id = api_client.submit_job(
            job_type=job_type,
            config_content=config_data["config_content"],
            config_s3_path=config_data["config_s3_path"],
            config_type=config_data["config_type"],
            dataset_name=dataset_name,
            description=description,
            **kwargs,
        )

        self.progress_display.show_submission(job_id, job_type)
        return job_id

    def _monitor_job(
        self, api_client: APIClient, job_id: str, job_type: str
    ) -> Dict[str, Any]:
        """
        Monitor job until completion.

        Args:
            api_client: API client for polling
            job_id: Job ID to monitor
            job_type: Job type for error messages

        Returns:
            Job result dictionary

        Raises:
            JobFailedException: If job fails
            RuntimeError: If polling fails
        """
        poller = JobPoller(api_client)

        try:
            result = poller.wait_for_completion(
                job_id=job_id, callback=self.progress_display.show_polling
            )
            self.progress_display.show_completion(result)
            return result

        except JobFailedException as e:
            self.progress_display.show_error(
                error=e, job_id=e.job_id, error_details=e.error_details
            )
            raise

        except Exception as e:
            self.progress_display.show_error(e, job_id)
            raise
