"""Unified configuration loader for Flow SDK.

This module provides a single, authoritative way to load Flow configuration
from all available sources with a clear precedence order.
"""

import logging
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Optional, Tuple

import yaml

from flow.errors import ConfigParserError

logger = logging.getLogger(__name__)


@dataclass
class ConfigSources:
    """All configuration data from various sources."""

    env_vars: Dict[str, str]
    keychain_api_key: Optional[str]
    config_file: Dict[str, Any]

    @property
    def api_key(self) -> Optional[str]:
        """Get API key with proper precedence: env > keychain > file."""
        return (
            self.env_vars.get("FCP_API_KEY")
            or self.keychain_api_key
            or self.config_file.get("api_key")
        )

    @property
    def provider(self) -> str:
        """Get provider with fallback to fcp."""
        return self.env_vars.get("FLOW_PROVIDER", "fcp")

    def get_fcp_config(self) -> Dict[str, Any]:
        """Get FCP-specific configuration with proper precedence."""
        config = {}

        # API URL
        config["api_url"] = (
            self.env_vars.get("FCP_API_URL")
            or self.config_file.get("fcp", {}).get("api_url")
            or self.config_file.get("api_url")  # Legacy location
            or "https://api.mlfoundry.com"
        )

        # Project
        project = (
            self.env_vars.get("FCP_DEFAULT_PROJECT")
            or self.config_file.get("fcp", {}).get("project")
            or self.config_file.get("project")  # Legacy location
        )
        if project:
            config["project"] = project

        # Region
        region = (
            self.env_vars.get("FCP_DEFAULT_REGION")
            or self.config_file.get("fcp", {}).get("region")
            or self.config_file.get("region")  # Legacy location
        )
        if region:
            config["region"] = region

        # SSH Keys
        ssh_keys_env = self.env_vars.get("FCP_SSH_KEYS")
        if ssh_keys_env:
            config["ssh_keys"] = [k.strip() for k in ssh_keys_env.split(",") if k.strip()]
        else:
            # Check config file
            ssh_keys = (
                self.config_file.get("fcp", {}).get("ssh_keys")
                or
                # Legacy: single key as list
                (
                    [self.config_file["default_ssh_key"]]
                    if "default_ssh_key" in self.config_file
                    else None
                )
            )
            if ssh_keys:
                config["ssh_keys"] = ssh_keys

        return config


class ConfigLoader:
    """Unified configuration loader with clear precedence and error handling."""

    def __init__(self, config_path: Optional[Path] = None):
        """Initialize the loader.

        Args:
            config_path: Path to config file (defaults to ~/.flow/config.yaml)
        """
        self.config_path = config_path or Path.home() / ".flow" / "config.yaml"

    def load_all_sources(self) -> ConfigSources:
        """Load configuration from all available sources.

        Returns:
            ConfigSources object with all available configuration
        """
        # 1. Environment variables (highest precedence)
        env_vars = dict(os.environ)

        # 2. Keychain API key
        keychain_api_key = self._load_from_keychain()

        # 3. Config file (lowest precedence)
        config_file = self._load_config_file()

        return ConfigSources(
            env_vars=env_vars, keychain_api_key=keychain_api_key, config_file=config_file
        )

    def _load_from_keychain(self) -> Optional[str]:
        """Load API key from system keychain.

        Returns:
            API key if found, None otherwise
        """
        # Skip keychain access in test environments
        if os.environ.get("FLOW_DISABLE_KEYCHAIN") == "1":
            return None

        try:
            from flow._internal.init.writer import ConfigWriter

            writer = ConfigWriter()
            return writer.read_api_key()
        except Exception as e:
            logger.debug(f"Could not load from keychain: {e}")
            return None

    def _load_config_file(self) -> Dict[str, Any]:
        """Load configuration from YAML file.

        Returns:
            Configuration dict, empty dict if file doesn't exist or has errors
        """
        if not self.config_path.exists():
            return {}

        try:
            with open(self.config_path) as f:
                content = yaml.safe_load(f) or {}
                if not isinstance(content, dict):
                    raise ConfigParserError(
                        f"Configuration file must contain a YAML dictionary, got {type(content).__name__}",
                        suggestions=[
                            "Ensure your config file starts with key: value pairs",
                            "Check that you haven't accidentally created a list or string",
                            "Example valid config: api_key: YOUR_KEY"
                        ],
                        error_code="CONFIG_002"
                    )
                return content
        except yaml.YAMLError as e:
            raise ConfigParserError(
                f"Invalid YAML syntax in {self.config_path}: {str(e)}",
                suggestions=[
                    "Check YAML indentation (use spaces, not tabs)",
                    "Ensure all strings with special characters are quoted",
                    "Validate syntax at yamllint.com",
                    "Common issue: unquoted strings containing colons"
                ],
                error_code="CONFIG_001"
            ) from e
        except ConfigParserError:
            raise
        except Exception as e:
            # For unexpected errors, still log and return empty dict for backward compatibility
            logger.warning(f"Unexpected error reading config file {self.config_path}: {e}")
            return {}

    def has_valid_config(self) -> bool:
        """Check if valid configuration exists.

        Returns:
            True if we have an API key from any source
        """
        sources = self.load_all_sources()
        api_key = sources.api_key
        return bool(api_key and not api_key.startswith("YOUR_"))

    def get_config_status(self) -> Tuple[bool, str]:
        """Get detailed configuration status.

        Returns:
            Tuple of (is_valid, status_message)
        """
        sources = self.load_all_sources()

        # Check API key
        if sources.env_vars.get("FCP_API_KEY"):
            api_key_source = "environment variable (FCP_API_KEY)"
        elif sources.keychain_api_key:
            api_key_source = "system keychain"
        elif sources.config_file.get("api_key"):
            api_key_source = "config file"
        else:
            return False, "No API key found in environment (FCP_API_KEY), keychain, or config file"

        api_key = sources.api_key
        if not api_key:
            return False, "No API key configured"

        if api_key.startswith("YOUR_"):
            return False, f"API key in {api_key_source} needs to be updated"

        # Check project
        fcp_config = sources.get_fcp_config()
        if not fcp_config.get("project"):
            return False, f"API key found in {api_key_source}, but no project configured"

        return True, f"Valid configuration found (API key from {api_key_source})"
