"""Utilities for reading and writing .env files."""

from __future__ import annotations

import re
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .categories import Category


def load_env_file(path: Path) -> dict[str, str]:
    """Load environment variables from a .env file.

    Handles:
    - KEY=VALUE format
    - Quoted values (single and double quotes)
    - Comments (lines starting with #)
    - Empty lines

    Args:
        path: Path to the .env file

    Returns:
        Dict mapping variable names to values
    """
    settings: dict[str, str] = {}

    if not path.exists():
        return settings

    with open(path, "r") as f:
        for line in f:
            line = line.strip()

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

            # Parse KEY=VALUE
            match = re.match(r"^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$", line)
            if not match:
                continue

            key = match.group(1)
            value = match.group(2).strip()

            # Handle quoted values
            if len(value) >= 2:
                if (value.startswith('"') and value.endswith('"')) or (
                    value.startswith("'") and value.endswith("'")
                ):
                    value = value[1:-1]

            settings[key] = value

    return settings


def save_env_file(
    path: Path,
    settings: dict[str, str],
    categories: list["Category"],
) -> None:
    """Save environment variables to a .env file.

    Organizes settings by category with headers and preserves any
    existing comments or settings not in our category list.

    Args:
        path: Path to the .env file
        settings: Dict mapping variable names to values
        categories: List of categories for organization
    """
    # Ensure parent directory exists
    path.parent.mkdir(parents=True, exist_ok=True)

    lines: list[str] = []

    # Header
    lines.append("#" * 80)
    lines.append("### AutoGPT - CONFIGURATION FILE")
    lines.append("#" * 80)
    lines.append("#")
    lines.append("# Generated by `autogpt config`")
    lines.append("#")
    lines.append("#" * 80)
    lines.append("")

    # Track which settings we've written
    written_keys: set[str] = set()

    # Write settings by category
    for category in categories:
        category_settings = []
        for env_var in category.env_vars:
            if env_var in settings and settings[env_var]:
                category_settings.append((env_var, settings[env_var]))
                written_keys.add(env_var)

        # Only write category if it has settings
        if category_settings:
            lines.append("#" * 80)
            lines.append(f"### {category.name.upper()}")
            lines.append("#" * 80)
            lines.append("")

            for key, value in category_settings:
                # Quote values that need it
                if _needs_quoting(value):
                    value = f'"{_escape_value(value)}"'
                lines.append(f"{key}={value}")

            lines.append("")

    # Write any remaining settings not in categories
    remaining = {k: v for k, v in settings.items() if k not in written_keys and v}
    if remaining:
        lines.append("#" * 80)
        lines.append("### OTHER SETTINGS")
        lines.append("#" * 80)
        lines.append("")

        for key, value in sorted(remaining.items()):
            if _needs_quoting(value):
                value = f'"{_escape_value(value)}"'
            lines.append(f"{key}={value}")

        lines.append("")

    # Write to file
    with open(path, "w") as f:
        f.write("\n".join(lines))


def _needs_quoting(value: str) -> bool:
    """Check if a value needs to be quoted in .env format."""
    if not value:
        return False
    # Quote if contains spaces, special chars, or starts/ends with whitespace
    if " " in value or "\t" in value:
        return True
    if value[0].isspace() or value[-1].isspace():
        return True
    if any(c in value for c in ["#", "'", '"', "\\", "\n", "\r"]):
        return True
    return False


def _escape_value(value: str) -> str:
    """Escape special characters in a value for .env format."""
    # Escape backslashes first
    value = value.replace("\\", "\\\\")
    # Escape double quotes
    value = value.replace('"', '\\"')
    # Escape newlines
    value = value.replace("\n", "\\n")
    value = value.replace("\r", "\\r")
    return value


def get_default_env_path() -> Path:
    """Get the default .env file path.

    Returns ~/.autogpt/.env for user-level configuration.
    """
    return Path.home() / ".autogpt" / ".env"


def find_env_file() -> Path | None:
    """Find an existing .env file in standard locations.

    Searches in order:
    1. Current working directory (./.env)
    2. User config directory (~/.autogpt/.env)
    3. XDG config directory (~/.config/autogpt/.env)

    Returns:
        Path to the first found .env file, or None if not found
    """
    search_paths = [
        Path.cwd() / ".env",
        Path.home() / ".autogpt" / ".env",
        Path.home() / ".config" / "autogpt" / ".env",
    ]

    for path in search_paths:
        if path.exists():
            return path

    return None
