"""Project discovery and configuration management."""

from __future__ import annotations

import json
import tomllib
from pathlib import Path

import tomli_w

from abreka.errors import ConfigNotFoundError
from abreka.models import Config


def find_abreka_dir(start: Path | None = None) -> Path:
    """Walk up from start (default: cwd) looking for an abreka/ directory with config.toml."""
    current = (start or Path.cwd()).resolve()
    for directory in [current, *current.parents]:
        candidate = directory / "abreka" / "config.toml"
        if candidate.is_file():
            return directory / "abreka"
    raise ConfigNotFoundError(
        f"No abreka/config.toml found in {current} or any parent directory. "
        "Run 'abreka init .' first."
    )


def project_root(abreka_dir: Path) -> Path:
    """Return the project root (parent of the abreka/ directory)."""
    return abreka_dir.parent


def load_config(abreka_dir: Path) -> Config:
    """Load and parse abreka/config.toml."""
    config_path = abreka_dir / "config.toml"
    if not config_path.is_file():
        raise ConfigNotFoundError(f"Config not found: {config_path}")
    with open(config_path, "rb") as f:
        data = tomllib.load(f)
    return Config.from_dict(data)


def save_config(config: Config, abreka_dir: Path) -> None:
    """Write config to abreka/config.toml."""
    config_path = abreka_dir / "config.toml"
    with open(config_path, "wb") as f:
        tomli_w.dump(config.to_dict(), f)


def discover_project(path: Path) -> tuple[str, str]:
    """Read pyproject.toml to extract the project name and discover the library name from src/ layout.

    Returns (project_name, lib_name).
    """
    pyproject_path = path / "pyproject.toml"
    if not pyproject_path.is_file():
        raise ConfigNotFoundError(f"No pyproject.toml found at {path}")

    with open(pyproject_path, "rb") as f:
        data = tomllib.load(f)

    project_name = data.get("project", {}).get("name", path.name)

    # Discover lib name from src/ layout
    src_dir = path / "src"
    lib_name = ""
    if src_dir.is_dir():
        for child in sorted(src_dir.iterdir()):
            if child.is_dir() and (child / "__init__.py").is_file():
                lib_name = child.name
                break

    if not lib_name:
        # Fall back to project name with hyphens replaced
        lib_name = project_name.replace("-", "_")

    return project_name, lib_name


def load_goal(abreka_dir: Path) -> str:
    """Read abreka/goal.md content."""
    goal_path = abreka_dir / "goal.md"
    if goal_path.is_file():
        return goal_path.read_text()
    return ""


PROMPT_ORDER = ("propose_exploit", "propose_explore", "implement", "test", "repair_run", "evaluate")


def load_prompts(abreka_dir: Path) -> dict[str, str]:
    """Read .md files from abreka/prompts/ in execution order."""
    prompts_dir = abreka_dir / "prompts"
    if not prompts_dir.is_dir():
        return {}
    result: dict[str, str] = {}
    for name in PROMPT_ORDER:
        p = prompts_dir / f"{name}.md"
        if p.is_file():
            result[name] = p.read_text()
    return result


def load_index(abreka_dir: Path) -> dict:
    """Read abreka/index.json."""
    index_path = abreka_dir / "index.json"
    if index_path.is_file():
        with open(index_path) as f:
            return json.load(f)
    return {}


def save_index(index: dict, abreka_dir: Path) -> None:
    """Write abreka/index.json."""
    index_path = abreka_dir / "index.json"
    with open(index_path, "w") as f:
        json.dump(index, f, indent=2)
        f.write("\n")
