"""Configuration file support for mcpaudit.

Loads .mcpaudit.yml from the current working directory.
Uses a simple YAML-subset parser (stdlib only, no external dependencies).
Falls back to PyYAML if available.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

CONFIG_FILENAME = ".mcpaudit.yml"

DEFAULT_CONFIG_CONTENT = """\
# mcpaudit configuration file
# See: https://github.com/cmiretf/mcpaudit

# Disable specific rules by ID
# exclude_rules:
#   - AUTH-001
#   - RATE-001

# Skip files/directories matching these glob patterns
# exclude_paths:
#   - "tests/*"
#   - "vendor/*"

# Only show findings at or above this severity level
# Values: critical, high, medium, low, info
# severity_threshold: info

# Default output format: text, json, html
# output_format: text

# Directory with custom rule modules (future extension)
# custom_rules_dir: ./custom_rules/
"""


@dataclass
class AuditConfig:
    """Parsed configuration for mcpaudit."""

    exclude_rules: list[str] = field(default_factory=list)
    exclude_paths: list[str] = field(default_factory=list)
    severity_threshold: str = "info"
    output_format: str = "text"
    custom_rules_dir: str = ""

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> AuditConfig:
        """Create config from a parsed dictionary."""
        return cls(
            exclude_rules=_as_list(data.get("exclude_rules", [])),
            exclude_paths=_as_list(data.get("exclude_paths", [])),
            severity_threshold=str(data.get("severity_threshold", "info")).lower(),
            output_format=str(data.get("output_format", "text")).lower(),
            custom_rules_dir=str(data.get("custom_rules_dir", "")),
        )


def _as_list(value: Any) -> list[str]:
    """Coerce a value to a list of strings."""
    if isinstance(value, list):
        return [str(v) for v in value]
    if isinstance(value, str):
        return [value] if value else []
    return []


def load_config(config_path: Path | None = None) -> AuditConfig:
    """Load configuration from a .mcpaudit.yml file.

    Args:
        config_path: Explicit path to config file. If None, searches CWD.

    Returns:
        AuditConfig with parsed values, or defaults if no config found.
    """
    if config_path is None:
        config_path = Path.cwd() / CONFIG_FILENAME

    if not config_path.exists():
        return AuditConfig()

    content = config_path.read_text(encoding="utf-8")
    data = _parse_simple_yaml(content)
    return AuditConfig.from_dict(data)


def create_default_config(directory: Path | None = None) -> Path:
    """Create a default .mcpaudit.yml configuration file.

    Args:
        directory: Directory to create the file in. Defaults to CWD.

    Returns:
        Path to the created config file.
    """
    if directory is None:
        directory = Path.cwd()
    config_path = directory / CONFIG_FILENAME
    config_path.write_text(DEFAULT_CONFIG_CONTENT, encoding="utf-8")
    return config_path


def _parse_simple_yaml(content: str) -> dict[str, Any]:
    """Parse a simple YAML subset (key: value, key: [list]).

    Supports:
    - key: value (string)
    - key:
        - item1
        - item2
    - Comments (#)
    - Quoted strings

    This is NOT a full YAML parser. It handles the subset used by .mcpaudit.yml.
    """
    # Try PyYAML first if available
    try:
        import yaml  # type: ignore[import-untyped]
        return yaml.safe_load(content) or {}
    except ImportError:
        pass

    result: dict[str, Any] = {}
    current_key: str | None = None
    current_list: list[str] | None = None

    for raw_line in content.splitlines():
        stripped = raw_line.strip()

        # Skip empty lines and comments
        if not stripped or stripped.startswith("#"):
            continue

        # Check for list item (starts with "- ")
        if stripped.startswith("- "):
            if current_key is not None and current_list is not None:
                value = stripped[2:].strip().strip("\"'")
                current_list.append(value)
            continue

        # Check for key: value
        if ":" in stripped:
            # Save previous list if any
            if current_key is not None and current_list is not None:
                result[current_key] = current_list

            colon_idx = stripped.index(":")
            key = stripped[:colon_idx].strip()
            value_part = stripped[colon_idx + 1:].strip()

            if value_part:
                # Inline value
                result[key] = value_part.strip("\"'")
                current_key = None
                current_list = None
            else:
                # Start of a list block
                current_key = key
                current_list = []

    # Save last list if pending
    if current_key is not None and current_list is not None:
        result[current_key] = current_list

    return result
