"""Configuration orchestration service."""

from pathlib import Path
from typing import Dict, List


class ConfigOrchestrator:
    """Coordinates config upload/download operations.

    Orchestrates workflow across FileHandler, PathResolver, and S3Operations.
    Single responsibility: workflow coordination only.
    """

    def __init__(self, file_handler, path_resolver, s3_operations):
        """Initialize with service dependencies.

        Args:
            file_handler: ConfigFileHandler instance
            path_resolver: ConfigPathResolver instance
            s3_operations: ConfigS3Operations instance
        """
        self.file_handler = file_handler
        self.path_resolver = path_resolver
        self.s3_operations = s3_operations

    def upload(self, local_path: str, sync: bool = True) -> Dict[str, int]:
        """Upload configs from local path to S3.

        Args:
            local_path: Local directory to upload from
            sync: If True, delete S3 files under same path first (clean slate). Default True.

        Returns:
            Dict with upload statistics (files_uploaded, bytes_uploaded, files_deleted)

        Raises:
            FileNotFoundError: If local_path doesn't exist
            PermissionError: If files can't be read
            Exception: If S3 upload fails
        """
        # Sync mode: delete S3 files under the upload path first for clean slate
        files_deleted = 0
        if sync:
            # Determine S3 prefix from local path
            # e.g., configs/discount -> czbillgen/configs/discount/
            local_path_obj = Path(local_path)
            relative_to_configs = self._extract_config_subpath(local_path_obj)
            files_deleted = self._delete_s3_configs_under_prefix(relative_to_configs)

        # Read files from local path
        local_path_obj = Path(local_path)
        files = self.file_handler.read_files(local_path_obj)

        # Upload each file to S3
        files_uploaded = 0
        bytes_uploaded = 0

        for file_path, content in files:
            # Convert local path to S3 key
            relative_path = file_path.relative_to(local_path_obj)
            s3_key = self.path_resolver.local_to_s3_key(str(relative_path))

            # Upload to S3
            self.s3_operations.upload_file(s3_key, content)

            files_uploaded += 1
            bytes_uploaded += len(content)

        return {
            'files_uploaded': files_uploaded,
            'bytes_uploaded': bytes_uploaded,
            'files_deleted': files_deleted
        }

    def _extract_config_subpath(self, local_path: Path) -> str:
        """Extract config subpath from local path.

        Args:
            local_path: Local path (e.g., configs/discount or ./configs/generate)

        Returns:
            Config subpath (e.g., discount or generate)
        """
        # Normalize path parts
        parts = [p for p in local_path.parts if p not in ('.', 'configs')]

        # If empty, means we're uploading entire configs/ dir
        if not parts:
            return ""

        # Return first part after configs/ (e.g., discount, generate, k8s)
        return parts[0]

    def _delete_s3_configs_under_prefix(self, subpath: str) -> int:
        """Delete config files from S3 under specific subpath.

        Args:
            subpath: Config subpath (e.g., "discount", "generate", "" for all)

        Returns:
            Number of files deleted
        """
        # Build prefix: czbillgen/configs/{subpath}/
        if subpath:
            prefix = self.path_resolver.list_prefix_from_path(subpath)
        else:
            prefix = self.path_resolver.list_prefix_from_path("czbillgen/configs/")

        s3_files = self.s3_operations.list_files(prefix)

        # Delete each file
        files_deleted = 0
        for file_info in s3_files:
            self.s3_operations.delete_file(file_info['key'])
            files_deleted += 1

        return files_deleted

    def download(self, s3_prefix: str = "czbillgen/configs/") -> Dict[str, int]:
        """Download configs from S3 to local directory.

        Args:
            s3_prefix: S3 prefix to download from (default: "czbillgen/configs/")

        Returns:
            Dict with download statistics (files_downloaded, bytes_downloaded)

        Raises:
            Exception: If S3 download fails
            PermissionError: If files can't be written locally
        """
        # Ensure S3 prefix is normalized
        normalized_prefix = self.path_resolver.list_prefix_from_path(s3_prefix)

        # List files from S3
        s3_files = self.s3_operations.list_files(normalized_prefix)

        # Download each file
        files_downloaded = 0
        bytes_downloaded = 0

        for file_info in s3_files:
            s3_key = file_info['key']

            # Convert S3 key to local path
            local_path = Path(self.path_resolver.s3_to_local_path(s3_key))

            # Download from S3
            content = self.s3_operations.download_file(s3_key)

            # Write to local file
            self.file_handler.write_file(local_path, content)

            files_downloaded += 1
            bytes_downloaded += len(content)

        return {
            'files_downloaded': files_downloaded,
            'bytes_downloaded': bytes_downloaded
        }

    def list_configs(self, prefix: str = "czbillgen/configs/") -> List[Dict[str, any]]:
        """List available configs in S3.

        Args:
            prefix: S3 prefix to list (default: "czbillgen/configs/")

        Returns:
            List of file metadata dicts

        Raises:
            Exception: If S3 list operation fails
        """
        # Normalize prefix
        normalized_prefix = self.path_resolver.list_prefix_from_path(prefix)

        # List files from S3
        return self.s3_operations.list_files(normalized_prefix)
