"""
Core environment management logic for dxlabs.
Handles the high-level business logic for pushing and pulling .env files.
"""

import os
from pathlib import Path
from typing import Dict, List, Optional

from ..config import Config
from ..providers.s3 import S3Provider


class EnvManager:
    """
    Manager for project environment (.env) files.
    Coordinates between the configuration and the storage provider.

    Attributes:
        config (Config): The project configuration.
        provider (S3Provider): The storage provider (currently S3).
    """

    def __init__(self, config: Config):
        """
        Initializes the EnvManager with a project configuration.

        Args:
            config (Config): The project settings (bucket, project ID, region, profile).
        """
        self.config = config
        self.provider = S3Provider(
            bucket=config.bucket, region=config.region, profile=config.profile
        )

    def discover_all_env_files(self) -> Dict[str, str]:
        """
        Scans the project to find all .env files and map them to environments.

        Returns:
            Dict[str, str]: A mapping of environment names to local file paths.
        """
        env_map = {}
        ignored_dirs = {
            ".git",
            "node_modules",
            "venv",
            ".venv",
            "__pycache__",
            "dist",
            "build",
        }

        for root, dirs, files in os.walk("."):
            dirs[:] = [d for d in dirs if d not in ignored_dirs]

            for file in files:
                full_path = os.path.join(root, file)
                # Normalize path for consistency
                rel_path = os.path.relpath(full_path, ".")

                # Case 1: .env.name
                if file.startswith(".env."):
                    env_name = file.replace(".env.", "")
                    if env_name:
                        env_map[env_name] = rel_path
                # Case 2: name.env (excluding just .env)
                elif file.endswith(".env") and file != ".env":
                    env_name = file.replace(".env", "")
                    if env_name:
                        env_map[env_name] = rel_path
                # Case 3: .env (default to development)
                elif file == ".env":
                    if "development" not in env_map:
                        env_map["development"] = rel_path

        return env_map

    def discover_remote_files(self) -> List[str]:
        """
        Lists all environment files currently stored on S3 for this project.

        Returns:
            List[str]: A list of relative paths recovered from S3 keys.
        """
        prefix = f"ENV/{self.config.project}/"
        keys = self.provider.list_files(prefix)

        # Recover relative paths from S3 keys
        # Example: ENV/my-proj/config/.env.staging -> config/.env.staging
        rel_paths = []
        for key in keys:
            if key.startswith(prefix):
                rel_path = key[len(prefix) :]
                # Skip if empty or a directory
                if not rel_path or rel_path.endswith("/"):
                    continue
                # Convert S3 forward slashes back to OS-specific path separators
                os_path = rel_path.replace("/", os.sep)
                rel_paths.append(os_path)
        return rel_paths

    def find_local_file(self, env_name: str) -> Optional[str]:
        """
        Smart discovery to find a specific .env file locally.
        """
        patterns = [f".env.{env_name}", f"{env_name}.env"]
        if env_name == "development":
            patterns.append(".env")

        for p in patterns:
            if os.path.exists(p):
                return p

        ignored_dirs = {
            ".git",
            "node_modules",
            "venv",
            ".venv",
            "__pycache__",
            "dist",
            "build",
        }
        for root, dirs, files in os.walk("."):
            dirs[:] = [d for d in dirs if d not in ignored_dirs]
            for p in patterns:
                if p in files:
                    full_path = os.path.join(root, p)
                    return os.path.relpath(full_path, ".")
        return None

    def get_remote_key(self, local_path: str) -> str:
        """
        Constructs the S3 key preserving the local relative path.
        Prefixes with 'ENV/{project_id}/'.

        Format: ENV/{project_id}/{relative_path_to_file}

        Args:
            local_path (str): The local path to the file.

        Returns:
            str: The fully qualified remote path/key with forward slashes.
        """
        # Ensure path is relative and clean
        rel_path = os.path.relpath(local_path, ".")
        # Convert Windows backslashes to S3 forward slashes
        s3_path = rel_path.replace(os.sep, "/")

        return f"ENV/{self.config.project}/{s3_path}"

    def push(self, local_path: str) -> bool:
        """Pushes a local file to remote storage."""
        remote_key = self.get_remote_key(local_path)
        return self.provider.upload(local_path, remote_key)

    def pull(self, local_path: str) -> bool:
        """Pulls a file from remote storage to local destination."""
        remote_key = self.get_remote_key(local_path)
        return self.provider.download(remote_key, local_path)

    def delete(self, local_path: str) -> bool:
        """Deletes a file from remote storage."""
        remote_key = self.get_remote_key(local_path)
        return self.provider.delete(remote_key)
