"""Root Typer app + callback + commands for session-picker."""

from __future__ import annotations

import os
from datetime import datetime

import typer
from rich.table import Table

from cli_framework import (
    ForceColorOption,
    NoColorOption,
    get_console,
    get_context,
    setup_logging,
)
from session_picker import __version__
from session_picker.context import SessionPickerContext
from session_picker.picker import pick_session
from session_picker.resume import resume_session
from session_store import SessionStore, default_registry
from session_store.models import SessionInfo

app = typer.Typer(
    name="session-picker",
    help="Interactive AI agent session picker with cross-directory support.",
    no_args_is_help=False,
    invoke_without_command=True,
    rich_markup_mode="rich",
    pretty_exceptions_enable=False,
)


def _load_sessions(
    ctx: SessionPickerContext,
    limit: int,
) -> list[SessionInfo]:
    """Load sessions from the store, applying filters."""
    store = SessionStore(registry=default_registry())
    sessions = store.list_sessions(tool=ctx.tool, limit=limit)

    if ctx.directory:
        sessions = [s for s in sessions if ctx.directory.lower() in s.working_directory.lower()]

    if not ctx.show_hidden:
        sessions = _filter_hidden_sessions(sessions)

    return sessions


def _filter_hidden_sessions(sessions: list[SessionInfo]) -> list[SessionInfo]:
    """Filter out hidden sessions."""
    return [s for s in sessions if not s.hidden]


@app.callback(invoke_without_command=True)
def main(
    ctx: typer.Context,
    tool: str = typer.Option(
        "devin", "--tool", "-t", help="AI agent tool (devin, opencode, copilot)"
    ),
    directory: str = typer.Option(
        None, "--directory", "-d", help="Filter by working directory substring"
    ),
    show_hidden: bool = typer.Option(False, "--show-hidden", help="Include hidden sessions"),
    limit: int = typer.Option(50, "--limit", "-l", help="Maximum number of sessions to show"),
    dry_run: bool = typer.Option(
        False, "--dry-run", help="Print session ID without launching devin"
    ),
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose logging"),
    no_color: NoColorOption = False,
    color: ForceColorOption = False,
    version: bool = typer.Option(False, "--version", "-V", help="Show version and exit"),
) -> None:
    """Interactive AI agent session picker with cross-directory support."""
    console = get_console()
    if version:
        console.print(f"session-picker {__version__}")
        raise typer.Exit()
    setup_logging(verbose)

    resolved_tool = tool or os.environ.get("SESSION_PICKER_TOOL", "devin")

    ctx.obj = SessionPickerContext(
        console=console,
        verbose=verbose,
        tool=resolved_tool,
        directory=directory,
        show_hidden=show_hidden,
    )

    # When no subcommand is given, the callback is the default action.
    if ctx.invoked_subcommand is None:
        app_ctx = ctx.obj
        assert isinstance(app_ctx, SessionPickerContext)

        sessions = _load_sessions(app_ctx, limit)
        selected = pick_session(sessions, console=app_ctx.console)

        if selected is None:
            raise typer.Exit(code=0)

        exit_code = resume_session(selected, dry_run=dry_run)
        raise typer.Exit(code=exit_code)


@app.command("list")
def list_sessions(
    ctx: typer.Context,
    tool: str = typer.Option(
        "devin", "--tool", "-t", help="AI agent tool (devin, opencode, copilot)"
    ),
    directory: str = typer.Option(
        None, "--directory", "-d", help="Filter by working directory substring"
    ),
    show_hidden: bool = typer.Option(False, "--show-hidden", help="Include hidden sessions"),
    limit: int = typer.Option(50, "--limit", "-l", help="Maximum number of sessions to list"),
) -> None:
    """List sessions in a table (non-interactive)."""
    app_ctx = get_context(ctx)
    assert isinstance(app_ctx, SessionPickerContext)

    resolved_tool = tool or app_ctx.tool
    resolved_directory = directory or app_ctx.directory
    resolved_show_hidden = show_hidden or app_ctx.show_hidden

    list_ctx = SessionPickerContext(
        console=app_ctx.console,
        verbose=app_ctx.verbose,
        tool=resolved_tool,
        directory=resolved_directory,
        show_hidden=resolved_show_hidden,
    )

    sessions = _load_sessions(list_ctx, limit)

    if not sessions:
        app_ctx.console.print("[dim]No sessions found[/dim]")
        return

    table = Table(title=f"Recent {list_ctx.tool.capitalize()} Sessions")
    table.add_column("Session ID", style="green")
    table.add_column("Title")
    table.add_column("Msgs", justify="right")
    table.add_column("Last Activity")
    table.add_column("Working Directory", style="dim")

    for s in sessions:
        table.add_row(
            s.session_id[:20],
            s.title or "",
            str(s.message_count),
            _format_last_activity(s.last_activity),
            s.working_directory,
        )

    app_ctx.console.print(table)


@app.command("resume")
def resume_command(
    ctx: typer.Context,
    session_id: str = typer.Argument(..., help="Session ID to resume"),
    dry_run: bool = typer.Option(
        False, "--dry-run", help="Print session ID without launching devin"
    ),
) -> None:
    """Resume a session by ID without the interactive picker."""
    exit_code = resume_session(session_id, dry_run=dry_run)
    raise typer.Exit(code=exit_code)


def _format_last_activity(last_activity: datetime) -> str:
    """Return a short human-readable relative time string."""
    now = datetime.now(last_activity.tzinfo) if last_activity.tzinfo else datetime.now()
    delta = now - last_activity
    total_seconds = int(delta.total_seconds())

    if total_seconds < 60:
        return "just now"
    if total_seconds < 3600:
        return f"{total_seconds // 60}m ago"
    if total_seconds < 86400:
        return f"{total_seconds // 3600}h ago"
    days = total_seconds // 86400
    if days < 30:
        return f"{days}d ago"
    return last_activity.strftime("%Y-%m-%d")


def run() -> None:
    """Run the CLI (for script entry point)."""
    app()


if __name__ == "__main__":
    run()
