"""Click CLI entry point for mykb."""

from pathlib import Path

import click
from rich.console import Console
from rich.table import Table

console = Console()


@click.group()
@click.option('-c', '--config-dir', type=click.Path(), default=None, help='Config directory (default: ~/.mykb)')
def cli(config_dir):
    """MYKB — Local CLI search engine for personal knowledge bases."""
    if config_dir:
        from .config import set_config_dir

        set_config_dir(Path(config_dir).expanduser().resolve())


# --- collection commands ---


@cli.group()
def collection():
    """Manage collections."""
    pass


@collection.command('add')
@click.argument('path')
@click.option('--name', '-n', required=True, help='Collection name')
@click.option('--source', '-s', default='obsidian', help='Source type (default: obsidian)')
@click.option('--mask', default='**/*.md', help='Glob pattern for files')
@click.option('--exclude', '-e', multiple=True, help='Exclude patterns')
@click.option('--description', '-d', default='', help='Description')
def collection_add(path, name, source, mask, exclude, description):
    """Add a new collection."""
    from .collection import add_collection

    col = add_collection(
        name=name,
        path=path,
        mask=mask,
        exclude=list(exclude),
        description=description,
        source=source,
    )
    console.print(f"[green]Added collection '{name}'[/green]")
    console.print(f'  Source: {col.source}')
    console.print(f'  Path: {col.path}')
    console.print(f'  Mask: {col.mask}')
    if col.exclude:
        console.print(f'  Exclude: {", ".join(col.exclude)}')


@collection.command('ls')
def collection_ls():
    """List all collections."""
    from .collection import list_collections

    collections = list_collections()
    if not collections:
        console.print('[yellow]No collections configured.[/yellow]')
        return

    table = Table(title='Collections')
    table.add_column('Name', style='bold cyan')
    table.add_column('Path')
    table.add_column('Mask')
    table.add_column('Description')

    for name, col in collections.items():
        table.add_row(name, col.path, col.mask, col.description)

    console.print(table)


@collection.command('rm')
@click.argument('name')
def collection_rm(name):
    """Remove a collection."""
    from .collection import remove_collection

    remove_collection(name)
    console.print(f"[green]Removed collection '{name}'[/green]")


# --- index command ---


@cli.command()
@click.option('--full', is_flag=True, help='Force full re-index')
@click.option('--collection', '-c', 'collection_name', default=None, help='Index specific collection')
@click.option('--embed', is_flag=True, help='Generate embeddings during indexing')
def index(full, collection_name, embed):
    """Index documents from collections into Meilisearch."""
    from .indexer import run_index

    run_index(collection_name=collection_name, full=full, with_embeddings=embed)


# --- embed command ---


@cli.command()
@click.option('--full', is_flag=True, help='Force full re-embedding')
@click.option('--collection', '-c', 'collection_name', default=None, help='Embed specific collection')
def embed(full, collection_name):
    """Generate/update embeddings for indexed documents."""
    from .embedder import Embedder
    from .indexer import get_default_backend

    backend = get_default_backend()
    embedder = Embedder()

    # Fetch all documents that need embeddings
    filter_str = f'collection = "{collection_name}"' if collection_name else None

    offset = 0
    total_updated = 0
    limit = 1000

    while True:
        docs = backend.get_documents('mykb', limit=limit, offset=offset, filter=filter_str)

        if not docs:
            break

        # Filter docs that need embedding (no _vectors or force full)
        to_embed = []
        for doc in docs:
            if full or not doc.get('_vectors'):
                to_embed.append(doc)

        if to_embed:
            texts = [d['content'] for d in to_embed]
            vectors = embedder.encode_documents(texts)

            id_vectors = {d['id']: vec for d, vec in zip(to_embed, vectors)}
            if id_vectors:
                backend.update_embeddings('mykb', id_vectors)
                total_updated += len(id_vectors)

        offset += len(docs)
        if len(docs) < limit:
            break

    console.print(f'[bold green]Updated embeddings for {total_updated} documents[/bold green]')


# --- search commands ---


def _search_options(f):
    """Common search options decorator."""
    f = click.option('-n', '--num', default=5, type=int, help='Number of results')(f)
    f = click.option('-c', '--collection', 'collection_name', default=None, help='Filter by collection')(f)
    f = click.option('--json', 'as_json', is_flag=True, help='Output as JSON')(f)
    f = click.option('--full', is_flag=True, help='Show full chunk content')(f)
    return f


@cli.command()
@click.argument('query')
@_search_options
def search(query, num, collection_name, as_json, full):
    """BM25 full-text search."""
    from .search import bm25_search, format_results_json, format_results_rich

    results = bm25_search(query, limit=num, collection=collection_name)
    if as_json:
        click.echo(format_results_json(results))
    else:
        format_results_rich(results, show_full=full)


@cli.command()
@click.argument('query')
@_search_options
def vsearch(query, num, collection_name, as_json, full):
    """Vector semantic search."""
    from .search import vector_search, format_results_json, format_results_rich

    results = vector_search(query, limit=num, collection=collection_name)
    if as_json:
        click.echo(format_results_json(results))
    else:
        format_results_rich(results, show_full=full)


@cli.command('query')
@click.argument('query_text')
@_search_options
@click.option('--ratio', default=0.5, type=float, help='Semantic ratio (0=BM25, 1=vector)')
def hybrid_query(query_text, num, collection_name, as_json, full, ratio):
    """Hybrid search (BM25 + vector)."""
    from .search import hybrid_search, format_results_json, format_results_rich

    results = hybrid_search(query_text, limit=num, collection=collection_name, semantic_ratio=ratio)
    if as_json:
        click.echo(format_results_json(results))
    else:
        format_results_rich(results, show_full=full)


# --- get command ---


@cli.command()
@click.argument('path')
def get(path):
    """Get original document content by source path."""
    from .collection import list_collections

    collections = list_collections()
    for name, col in collections.items():
        full_path = Path(col.path) / path
        if full_path.exists():
            content = full_path.read_text(encoding='utf-8')
            console.print(content)
            return

    console.print(f'[red]File not found in any collection: {path}[/red]')


# --- status command ---


@cli.command()
def status():
    """Show index status, collection info, and document counts."""
    from .collection import list_collections
    from .config import get_backend_config
    from .indexer import get_default_backend
    from .sources import get_source

    # Collections info
    collections = list_collections()
    console.print('[bold]Collections:[/bold]')
    if not collections:
        console.print('  [yellow]None configured[/yellow]')
    else:
        for name, col in collections.items():
            source = get_source(col.source, name, col.model_dump())
            item_count = sum(1 for _ in source.scan())
            console.print(f'  [cyan]{name}[/cyan] ({col.source}): {col.path} ({item_count} items)')

    # Backend info
    backend_type, backend_config = get_backend_config()
    console.print(f'\n[bold]Backend ({backend_type}):[/bold]')

    backend = get_default_backend()
    health = backend.health_check()
    console.print(f'  Status: [green]{health.get("status", "unknown")}[/green]')

    if 'url' in health:
        console.print(f'  URL: {health["url"]}')

    stats = backend.get_stats('mykb')
    doc_count = stats.get('total_documents', 0)
    console.print(f'  Documents: {doc_count}')
