"""
Lightweight .env file manager — zero external dependencies.

Reads/writes ~/.ag402/.env with robust parsing that handles:
- Quoted values (single/double)
- Values containing '=' signs
- Inline comments (only after unquoted values)
- Empty lines and comment-only lines
- Graceful skip on unparseable lines (warn, don't crash)
"""

from __future__ import annotations

import logging
import os
import re
from pathlib import Path

logger = logging.getLogger(__name__)

_DEFAULT_ENV_DIR = Path.home() / ".ag402"
_DEFAULT_ENV_PATH = _DEFAULT_ENV_DIR / ".env"

# Regex: KEY=VALUE with optional quoting
# Captures: key, optional quote char, value
_LINE_RE = re.compile(
    r"""
    \A
    \s*
    (?:export\s+)?            # optional 'export' prefix
    ([A-Za-z_][A-Za-z0-9_]*)  # key
    \s*=\s*                    # equals sign
    (?:
        "((?:[^"\\]|\\.)*)"   # double-quoted value (group 2)
      | '([^']*)'             # single-quoted value (group 3)
      | ([^\#\n]*)            # unquoted value (group 4)
    )
    """,
    re.VERBOSE,
)


def _parse_line(line: str) -> tuple[str, str] | None:
    """Parse a single .env line into (key, value) or None."""
    line = line.strip()
    if not line or line.startswith("#"):
        return None

    m = _LINE_RE.match(line)
    if not m:
        logger.warning("Skipping unparseable .env line: %s", line[:80])
        return None

    key = m.group(1)
    if m.group(2) is not None:
        # Double-quoted: unescape backslash sequences
        value = m.group(2).replace('\\"', '"').replace("\\n", "\n").replace("\\\\", "\\")
    elif m.group(3) is not None:
        # Single-quoted: literal
        value = m.group(3)
    else:
        # Unquoted: strip trailing whitespace / inline comment
        value = m.group(4).strip()
    return key, value


def parse_env_file(path: str | Path | None = None) -> dict[str, str]:
    """Parse a .env file and return a dict of key-value pairs.

    Returns an empty dict if the file doesn't exist.
    Skips unparseable lines with a warning (never crashes).
    """
    path = Path(path) if path else _DEFAULT_ENV_PATH
    if not path.exists():
        return {}

    result: dict[str, str] = {}
    try:
        with open(path) as f:
            for lineno, raw_line in enumerate(f, 1):
                try:
                    parsed = _parse_line(raw_line)
                    if parsed:
                        result[parsed[0]] = parsed[1]
                except Exception as exc:
                    logger.warning("Error parsing .env line %d: %s", lineno, exc)
    except OSError as exc:
        logger.warning("Could not read .env file %s: %s", path, exc)

    return result


def load_dotenv(path: str | Path | None = None, *, override: bool = False) -> int:
    """Load .env file into os.environ.

    Args:
        path: Path to .env file. Defaults to ~/.ag402/.env.
        override: If True, overwrite existing env vars. Default False.

    Returns:
        Number of variables loaded.
    """
    entries = parse_env_file(path)
    count = 0
    for key, value in entries.items():
        if override or key not in os.environ:
            os.environ[key] = value
            count += 1
    return count


def save_env_file(
    entries: dict[str, str],
    path: str | Path | None = None,
    *,
    merge: bool = True,
) -> None:
    """Write key-value pairs to .env file.

    Args:
        entries: Dict of key-value pairs to write.
        path: Path to .env file. Defaults to ~/.ag402/.env.
        merge: If True, merge with existing entries. If False, overwrite.
    """
    path = Path(path) if path else _DEFAULT_ENV_PATH

    # Ensure directory exists
    path.parent.mkdir(parents=True, exist_ok=True)

    existing: dict[str, str] = {}
    if merge:
        existing = parse_env_file(path)

    # Merge: new entries override existing
    combined = {**existing, **entries}

    lines: list[str] = [
        "# Ag402 configuration — generated by `ag402 setup`",
        "# Do not edit manually unless you know what you're doing.",
        "",
    ]
    for key, value in sorted(combined.items()):
        # Quote values that contain special characters
        if _needs_quoting(value):
            escaped = value.replace("\\", "\\\\").replace('"', '\\"')
            lines.append(f'{key}="{escaped}"')
        else:
            lines.append(f"{key}={value}")

    with open(path, "w") as f:
        f.write("\n".join(lines) + "\n")

    # Restrictive permissions (owner-only)
    import contextlib
    with contextlib.suppress(OSError):
        os.chmod(path, 0o600)


def set_env_value(key: str, value: str, path: str | Path | None = None) -> None:
    """Set a single key-value pair in the .env file (merge mode)."""
    save_env_file({key: value}, path=path, merge=True)


def get_env_path() -> Path:
    """Return the default .env file path."""
    return _DEFAULT_ENV_PATH


def _needs_quoting(value: str) -> bool:
    """Check if a value needs to be quoted in .env format."""
    if not value:
        return True
    # Quote if contains spaces, quotes, #, newlines, or leading/trailing whitespace
    if value != value.strip():
        return True
    return any(ch in value for ch in (' ', '"', "'", '#', '\n', '\\'))
