import os
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, Optional

from .logger import Logger


class EnvLoaderError(Exception):
    pass


@dataclass
class LoadedEnv:
    values: Dict[str, str]
    used_env_path: Optional[Path]
    warned_missing: bool


def parse_env_file(env_path: Path) -> Dict[str, str]:
    values: Dict[str, str] = {}
    with env_path.open("r", encoding="utf-8") as handle:
        for raw_line in handle:
            line = raw_line.strip()
            if not line or line.startswith("#"):
                continue
            if "=" not in line:
                continue
            key, val = line.split("=", 1)
            values[key.strip()] = val.strip()
    return values


def load_env(
    env_path: Optional[str],
    *,
    logger: Optional[Logger] = None,
    cwd: Optional[Path] = None,
) -> LoadedEnv:
    log = logger or Logger()
    cwd = cwd or Path.cwd()

    resolved_env_path = Path(env_path) if env_path else cwd / ".env"
    from_env_file: Dict[str, str] = {}
    used_env_path: Optional[Path] = None
    warned_missing = False

    if env_path:
        if not resolved_env_path.exists() or not resolved_env_path.is_file():
            raise EnvLoaderError(f".env not found or unreadable at {resolved_env_path}")
        from_env_file = parse_env_file(resolved_env_path)
        used_env_path = resolved_env_path
    else:
        if resolved_env_path.exists() and resolved_env_path.is_file():
            from_env_file = parse_env_file(resolved_env_path)
            used_env_path = resolved_env_path
        else:
            warned_missing = True
            log.warn(f".env not found at {resolved_env_path}, using env only")

    if env_path:
        combined: Dict[str, str] = dict(from_env_file)
    else:
        combined = dict(os.environ)
        combined.update(from_env_file)

    return LoadedEnv(values=combined, used_env_path=used_env_path, warned_missing=warned_missing)
