"""Docstream CLI — Typer application (spec §6.1)."""
from __future__ import annotations

import os
import typer
from rich.console import Console
from rich.table import Table

from .client import DocstreamClient, _renderer_dict, _resolve_base_url
from .process import start_service, status_service, stop_service
from .transport import parse_source_uri

app = typer.Typer(
    name="docstream",
    help="Docstream CLI — manage contexts and control the service.",
    no_args_is_help=True,
)
console = Console()


@app.callback()
def main(
    log_level: str = typer.Option(
        None,
        "--log-level",
        help="Log level (DEBUG, INFO, WARNING, ERROR). Defaults to env DOCSTREAM_LOG_LEVEL or WARNING.",
        envvar="DOCSTREAM_LOG_LEVEL",
    ),
) -> None:
    """Docstream CLI — manage contexts and control the service."""
    if log_level:
        os.environ["DOCSTREAM_LOG_LEVEL"] = log_level.upper()


def _get_client(api_url: str | None) -> DocstreamClient:
    return DocstreamClient(base_url=_resolve_base_url(api_url))


def _print_context(ctx: dict) -> None:
    """Pretty-print a single context."""
    console.print(f"[bold cyan]{ctx.get('id')}[/bold cyan]")
    renderer = ctx.get("renderer")
    if renderer:
        parts = []
        if renderer.get("md_engine"):
            parts.append(f"md={renderer['md_engine']}")
        if renderer.get("hl_engine"):
            parts.append(f"hl={renderer['hl_engine']}")
        if parts:
            console.print(f"  renderer: {', '.join(parts)}")
    sources = ctx.get("sources") or []
    if not sources:
        console.print("  [dim]no sources[/dim]")
        return
    for src in sources:
        slug = src.get("slug", "?")
        transport = src.get("transport", "?")
        location = src.get("location", "?")
        alias = src.get("alias") or src.get("source_alias") or ""
        label = f"alias={alias}" if alias else ""
        console.print(f"  • [green]{slug}[/green] ({transport}) {location} {label}".rstrip())


# --------------------------------------------------------------------------- create
@app.command()
def create(
    context: str = typer.Option(..., "--context", help="Context id (URL-safe slug)."),
    md_engine: str | None = typer.Option(
        None, "--md-engine", help="Markdown engine: pandoc | python-markdown."
    ),
    hl_engine: str | None = typer.Option(
        None, "--hl-engine", help="Highlight engine: pygments | none."
    ),
    api_url: str | None = typer.Option(
        None, "--api-url", help="API base URL (overrides DOCSTREAM_API_URL)."
    ),
) -> None:
    """Create a context with an optional renderer default."""
    client = _get_client(api_url)
    renderer = _renderer_dict(md_engine, hl_engine)
    result = client.create_context(context, renderer=renderer)
    console.print(f"[green]Created[/green] context [bold cyan]{context}[/bold cyan].")
    _print_context(result)


# --------------------------------------------------------------------------- update
@app.command()
def update(
    context: str = typer.Option(..., "--context", help="Context id."),
    md_engine: str | None = typer.Option(None, "--md-engine"),
    hl_engine: str | None = typer.Option(None, "--hl-engine"),
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Update a context's renderer default."""
    client = _get_client(api_url)
    renderer = _renderer_dict(md_engine, hl_engine)
    result = client.update_context(context, renderer=renderer)
    console.print(f"[green]Updated[/green] context [bold cyan]{context}[/bold cyan].")
    _print_context(result)


# --------------------------------------------------------------------------- add
@app.command()
def add(
    context: str = typer.Option(..., "--context", help="Context id."),
    source: str = typer.Option(..., "--source", help="Source URI (see §6.5)."),
    alias: str | None = typer.Option(None, "--alias", help="Alias for the source."),
    md_engine: str | None = typer.Option(None, "--md-engine"),
    hl_engine: str | None = typer.Option(None, "--hl-engine"),
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Add a source to a context."""
    transport, location = parse_source_uri(source)
    client = _get_client(api_url)
    renderer = _renderer_dict(md_engine, hl_engine)
    result = client.add_source(
        context, transport=transport, location=location, alias=alias, renderer=renderer
    )
    slug = result.get("slug", "?")
    console.print(
        f"[green]Added[/green] source [green]{slug}[/green] "
        f"({transport}) to context [bold cyan]{context}[/bold cyan]."
    )


# --------------------------------------------------------------------------- remove
@app.command()
def remove(
    context: str = typer.Option(..., "--context", help="Context id."),
    slug: str = typer.Option(..., "--slug", help="Source slug to remove."),
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Remove a source from a context."""
    client = _get_client(api_url)
    client.remove_source(context, slug)
    console.print(
        f"[green]Removed[/green] source [green]{slug}[/green] from context "
        f"[bold cyan]{context}[/bold cyan]."
    )


# --------------------------------------------------------------------------- list
@app.command(name="list")
def list_contexts(
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Show all contexts and their sources."""
    client = _get_client(api_url)
    data = client.list_contexts()
    contexts = data.get("contexts") if isinstance(data, dict) else data
    if not contexts:
        console.print("[dim]No contexts registered.[/dim]")
        return
    table = Table(title="Docstream Contexts")
    table.add_column("Context", style="bold cyan")
    table.add_column("Renderer", style="magenta")
    table.add_column("Sources", style="green")
    for ctx in contexts:
        cid = ctx.get("id", "?")
        renderer = ctx.get("renderer") or {}
        rparts = []
        if renderer.get("md_engine"):
            rparts.append(f"md={renderer['md_engine']}")
        if renderer.get("hl_engine"):
            rparts.append(f"hl={renderer['hl_engine']}")
        rstr = ", ".join(rparts) if rparts else "-"
        sources = ctx.get("sources") or []
        slugs = ", ".join(s.get("slug", "?") for s in sources) if sources else "-"
        table.add_row(cid, rstr, slugs)
    console.print(table)


# --------------------------------------------------------------------------- delete
@app.command()
def delete(
    context: str = typer.Option(..., "--context", help="Context id."),
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Delete a context."""
    client = _get_client(api_url)
    client.delete_context(context)
    console.print(f"[green]Deleted[/green] context [bold cyan]{context}[/bold cyan].")


# --------------------------------------------------------------------------- start
@app.command()
def start(
    host: str = typer.Option("127.0.0.1", "--host", help="Bind host."),
    port: int = typer.Option(49202, "--port", help="Bind port."),
) -> None:
    """Start the background service (uvicorn)."""
    start_service(host=host, port=port)


# --------------------------------------------------------------------------- stop
@app.command()
def stop() -> None:
    """Stop the background service."""
    stop_service()


# --------------------------------------------------------------------------- status
@app.command()
def status(
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Show service status."""
    status_service(api_url=api_url)


# --------------------------------------------------------------------------- reload
@app.command()
def reload(
    context: str = typer.Option(..., "--context", help="Context id."),
    api_url: str | None = typer.Option(None, "--api-url"),
) -> None:
    """Force a context reload."""
    client = _get_client(api_url)
    client.reload_context(context)
    console.print(
        f"[green]Reloaded[/green] context [bold cyan]{context}[/bold cyan]."
    )


if __name__ == "__main__":
    app()
