"""Reindex command - wipe graph data and re-index from scratch."""

import json as _json
import sys
import time
from pathlib import Path
from typing import Annotated, Optional

import httpx
import typer

from nogic.config import Config, CONFIG_DIR, is_dev_mode, get_api_url
from nogic.ignore import build_ignore_matcher
from nogic.watcher import SyncService
from nogic.api import NogicClient
from nogic import ui


def _emit_json(event: str, **kwargs):
    """Emit a single NDJSON line to stdout."""
    payload = {"event": event, "timestamp": int(time.time()), **kwargs}
    sys.stdout.write(_json.dumps(payload) + "\n")
    sys.stdout.flush()


def reindex(
    directory: Annotated[Path, typer.Argument(help="Path to the project directory.")] = Path("."),
    ignore: Annotated[Optional[list[str]], typer.Option("--ignore", help="Patterns to ignore.")] = None,
    yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation.")] = False,
    format: Annotated[Optional[str], typer.Option("--format", help="Output format: text or json.")] = None,
):
    """Wipe graph data and re-index the entire project."""
    directory = directory.resolve()
    nogic_dir = directory / CONFIG_DIR
    ignore = ignore or []
    json_mode = format == "json"

    if not nogic_dir.exists():
        ui.error("Not a Nogic project.")
        ui.dim("Run `nogic init` to initialize your project.")
        raise typer.Exit(1)

    config = Config.load(directory)

    if not config.api_key:
        ui.error("Not logged in.")
        ui.dim("Run `nogic login` to authenticate.")
        raise typer.Exit(1)

    if not config.project_id:
        ui.error("No project configured.")
        ui.dim("Run `nogic init` to initialize your project.")
        raise typer.Exit(1)

    if not json_mode:
        if is_dev_mode():
            ui.dev_banner(get_api_url())

        if not yes:
            ui.banner("nogic reindex")
            ui.kv("Project", config.project_name or f"{config.project_id[:8]}...")
            ui.kv("Directory", str(directory))
            ui.console.print()
            ui.warn("This will delete all graph data and re-index from scratch.")
            ui.console.print()
            if not typer.confirm("Continue?", default=False):
                ui.dim("Aborted.")
                raise typer.Exit(0)

    client = NogicClient(config)
    nodes_deleted = 0

    try:
        if json_mode:
            _emit_json("progress", phase="wiping")
        else:
            wipe_ctx = ui.status_spinner("Wiping graph data...")
            wipe_ctx.__enter__()

        try:
            result = client.wipe_project_graph(config.project_id)
            nodes_deleted = result.nodes_deleted
        except httpx.HTTPStatusError as e:
            if e.response.status_code == 404:
                pass
            else:
                if json_mode:
                    _emit_json("error", message=f"Error wiping graph ({e.response.status_code})")
                else:
                    ui.error(f"Error wiping graph ({e.response.status_code})")
                raise typer.Exit(1)

        if not json_mode:
            wipe_ctx.__exit__(None, None, None)

        if json_mode:
            _emit_json("wiped", nodes_deleted=nodes_deleted)
        elif nodes_deleted:
            ui.info(f"Deleted {nodes_deleted} nodes")

        should_ignore = build_ignore_matcher(directory, extra_patterns=ignore)
        log_fn = (lambda msg: None) if json_mode else (lambda msg: ui.dim(f"  {msg}"))
        sync_service = SyncService(config, directory, log=log_fn, json_mode=json_mode)

        sync_service.initial_scan(directory, should_ignore)
        sync_service.close()

        if not json_mode:
            ui.console.print()
            ui.success("Reindex complete!")
            if nodes_deleted > 0:
                ui.dim(f"  Old nodes deleted: {nodes_deleted}")
            ui.console.print()
            ui.dim("Run 'nogic watch' to continue monitoring for changes.")

    finally:
        client.close()
