"""agentkit readme command — inject agent quality badge into README.md."""
from __future__ import annotations

import re
from pathlib import Path
from typing import Optional

import typer
from rich.console import Console

from agentkit_cli.commands.badge_cmd import (
    build_badge_url,
    compute_badge_score,
    score_to_color,
)

console = Console()

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------

PYPI_LINK = "https://pypi.org/project/agentkit-cli/"
BADGE_PATTERN = re.compile(r"\[!\[agent quality\]")
_GENERATED_FOOTER = "Generated by [agentkit-cli](https://pypi.org/project/agentkit-cli/)."


# ---------------------------------------------------------------------------
# Section helpers
# ---------------------------------------------------------------------------

def build_section(score: int, section_header: str = "## Agent Quality") -> str:
    """Build the full markdown section to inject."""
    badge_url = build_badge_url(score)
    badge_md = f"[![agent quality]({badge_url})]({PYPI_LINK})"
    return (
        f"{section_header}\n"
        f"\n"
        f"{badge_md}\n"
        f"\n"
        f"{_GENERATED_FOOTER}\n"
    )


def _find_section_bounds(lines: list[str], section_header: str) -> tuple[int, int] | None:
    """Return (start, end) line indices of an existing injected section, or None."""
    header_norm = section_header.strip().lower()
    start_idx = None
    for i, line in enumerate(lines):
        if line.strip().lower() == header_norm:
            start_idx = i
            break
        # Also detect by badge pattern (header may vary)
        if BADGE_PATTERN.search(line):
            # Walk back to find the nearest header above
            j = i - 1
            while j >= 0 and lines[j].strip() == "":
                j -= 1
            if j >= 0 and lines[j].strip().startswith("#"):
                start_idx = j
            else:
                start_idx = i
            break

    if start_idx is None:
        return None

    # Walk forward: end is after the generated footer line (or next non-blank)
    end_idx = start_idx + 1
    while end_idx < len(lines):
        stripped = lines[end_idx].strip()
        if stripped == _GENERATED_FOOTER.strip():
            end_idx += 1
            break
        # Stop if we hit another section header that isn't the first line
        if stripped.startswith("#") and end_idx > start_idx + 1:
            break
        end_idx += 1

    return (start_idx, end_idx)


def inject_section(content: str, score: int, section_header: str = "## Agent Quality") -> str:
    """Inject or update the badge section. Returns modified content string."""
    new_section = build_section(score, section_header)
    lines = content.splitlines(keepends=True)

    bounds = _find_section_bounds(lines, section_header)

    if bounds is not None:
        start, end = bounds
        # Replace the existing section
        # Preserve any trailing content after the section
        new_lines = lines[:start] + [line + ("\n" if not line.endswith("\n") else "") for line in new_section.splitlines()] + lines[end:]
        return "".join(new_lines)
    else:
        # Append to end of file
        # Ensure there's a blank line separator
        if content and not content.endswith("\n\n"):
            if content.endswith("\n"):
                content += "\n"
            else:
                content += "\n\n"
        return content + new_section


def remove_section(content: str, section_header: str = "## Agent Quality") -> str:
    """Remove the injected section. Returns modified content string."""
    lines = content.splitlines(keepends=True)
    bounds = _find_section_bounds(lines, section_header)

    if bounds is None:
        return content

    start, end = bounds

    # Also eat a leading blank line before the section (if any)
    prefix_end = start
    if start > 0 and lines[start - 1].strip() == "":
        prefix_end = start - 1

    new_lines = lines[:prefix_end] + lines[end:]
    # Strip trailing blank lines at the end
    while new_lines and new_lines[-1].strip() == "":
        new_lines.pop()
    result = "".join(new_lines)
    if result and not result.endswith("\n"):
        result += "\n"
    return result


# ---------------------------------------------------------------------------
# Command
# ---------------------------------------------------------------------------

def readme_command(
    readme: Optional[Path],
    dry_run: bool,
    remove: bool,
    section_header: str,
    path: Optional[Path],
    score_override: Optional[int],
) -> None:
    """Inject or update the agent quality badge in README.md."""
    # Resolve project directory
    cwd = (path or Path.cwd()).resolve()

    # Locate README
    if readme is not None:
        readme_path = readme.resolve()
    else:
        readme_path = cwd / "README.md"

    if not readme_path.exists():
        console.print(f"[red]README not found: {readme_path}[/red]")
        raise typer.Exit(code=1)

    content = readme_path.read_text(encoding="utf-8")

    # --remove mode
    if remove:
        new_content = remove_section(content, section_header)
        if new_content == content:
            console.print("[yellow]No injected section found — nothing removed.[/yellow]")
            return
        if dry_run:
            console.print("[bold]Dry run — would remove badge section.[/bold]")
            console.print(f"[dim]From: {readme_path}[/dim]")
        else:
            readme_path.write_text(new_content, encoding="utf-8")
            console.print(f"[green]Removed badge section from {readme_path.name}[/green]")
        return

    # Compute score
    if score_override is not None:
        score = max(0, min(100, score_override))
    else:
        if not dry_run:
            console.print("\n[dim]Computing agent quality score...[/dim]")
        result = compute_badge_score(str(cwd))
        score = result["score"]

    color = score_to_color(score)
    new_content = inject_section(content, score, section_header)

    if dry_run:
        console.print(f"\n[bold]Dry run — would inject into {readme_path.name}:[/bold]")
        console.print()
        console.print(build_section(score, section_header))
        console.print(f"[dim]Agent quality: {score}/100 ({color})[/dim]")
        return

    readme_path.write_text(new_content, encoding="utf-8")
    console.print(f"\n[green]Updated {readme_path.name}[/green] — agent quality: [{color}]{score}/100[/{color}] ({color})")
