"""CLI commands for vector memory.

Provides commands for indexing, querying, and managing vector memory.
"""

from __future__ import annotations

import json
from pathlib import Path

import click

from oclawma.memory.embeddings import (
    KimiEmbeddingProvider,
    OllamaEmbeddingProvider,
)
from oclawma.memory.indexer import MemoryIndexer
from oclawma.memory.query import MemoryQuery
from oclawma.memory.store import VectorMemoryStore


def get_embedding_provider(
    provider: str,
    model: str | None = None,
) -> KimiEmbeddingProvider | OllamaEmbeddingProvider:
    """Get an embedding provider.

    Args:
        provider: Provider type ("kimi" or "ollama").
        model: Optional model override.

    Returns:
        Configured embedding provider.
    """
    if provider == "kimi":
        kwargs = {}
        if model:
            kwargs["model"] = model
        return KimiEmbeddingProvider(**kwargs)
    else:
        kwargs = {}
        if model:
            kwargs["model"] = model
        return OllamaEmbeddingProvider(**kwargs)


@click.group(name="memory")
def memory_cli() -> None:
    """Vector memory management commands.

    Index and query memories using vector similarity search.
    """
    pass


@memory_cli.command(name="index")
@click.option(
    "--provider",
    type=click.Choice(["kimi", "ollama", "auto"], case_sensitive=False),
    default="auto",
    help="Embedding provider to use.",
)
@click.option(
    "--model",
    help="Embedding model to use.",
)
@click.option(
    "--memory-file",
    type=click.Path(exists=True, path_type=Path),
    default=None,
    help="Path to MEMORY.md file.",
)
@click.option(
    "--workspace",
    type=click.Path(exists=True, file_okay=False, path_type=Path),
    default=None,
    help="Path to workspace directory.",
)
@click.option(
    "--daily-notes",
    is_flag=True,
    help="Index daily notes files.",
)
def index_memory(
    provider: str,
    model: str | None,
    memory_file: Path | None,
    workspace: Path | None,
    daily_notes: bool,
) -> None:
    """Index memory files into vector store.

    Examples:
        oclawma memory index
        oclawma memory index --provider kimi
        oclawma memory index --daily-notes
    """
    # Determine paths
    if workspace is None:
        from oclawma.config import get_workspace_dir

        workspace = get_workspace_dir()

    if memory_file is None:
        memory_file = workspace / "MEMORY.md"

    # Resolve provider
    if provider == "auto":
        import os

        if os.environ.get("KIMI_API_KEY"):
            provider = "kimi"
            click.echo("Using Kimi embedding provider (auto-detected)")
        else:
            provider = "ollama"
            click.echo("Using Ollama embedding provider (auto-detected)")

    # Create embedding provider
    try:
        embedding_provider = get_embedding_provider(provider, model)
    except ValueError as e:
        raise click.ClickException(str(e)) from e

    # Create store and indexer
    store = VectorMemoryStore(embedding_dimension=embedding_provider.get_dimension())
    indexer = MemoryIndexer()

    total_indexed = 0

    # Index MEMORY.md
    if memory_file.exists():
        click.echo(f"Indexing {memory_file}...")
        count = indexer.index_memory_file(memory_file, embedding_provider, store)
        click.echo(f"  Indexed {count} chunks")
        total_indexed += count
    else:
        click.echo(f"Warning: {memory_file} not found")

    # Index daily notes
    if daily_notes:
        memory_dir = workspace / "memory"
        if memory_dir.exists():
            for note_file in sorted(memory_dir.glob("20[0-9][0-9]-*.md")):
                click.echo(f"Indexing {note_file.name}...")
                count = indexer.index_memory_file(note_file, embedding_provider, store)
                click.echo(f"  Indexed {count} chunks")
                total_indexed += count

    # Show stats
    stats = store.get_stats()
    click.echo(f"\n✓ Total chunks indexed: {total_indexed}")
    click.echo(f"✓ Total in store: {stats['total_chunks']}")


@memory_cli.command(name="query")
@click.argument("query_text")
@click.option(
    "--provider",
    type=click.Choice(["kimi", "ollama", "auto"], case_sensitive=False),
    default="auto",
    help="Embedding provider to use.",
)
@click.option(
    "--model",
    help="Embedding model to use.",
)
@click.option(
    "--top-k",
    type=int,
    default=5,
    help="Number of results to return.",
)
@click.option(
    "--format",
    "output_format",
    type=click.Choice(["text", "markdown", "json"], case_sensitive=False),
    default="text",
    help="Output format.",
)
@click.option(
    "--source",
    help="Filter by source.",
)
@click.option(
    "--type",
    "chunk_type",
    help="Filter by chunk type.",
)
def query_memory(
    query_text: str,
    provider: str,
    model: str | None,
    top_k: int,
    output_format: str,
    source: str | None,
    chunk_type: str | None,
) -> None:
    """Query the vector memory store.

    Examples:
        oclawma memory query "What do I know about Mike?"
        oclawma memory query "technical setup" --top-k 10
        oclawma memory query "boundaries" --format markdown
    """
    # Resolve provider
    if provider == "auto":
        import os

        provider = "kimi" if os.environ.get("KIMI_API_KEY") else "ollama"

    # Create embedding provider
    try:
        embedding_provider = get_embedding_provider(provider, model)
    except ValueError as e:
        raise click.ClickException(str(e)) from e

    # Create store and query interface
    store = VectorMemoryStore(embedding_dimension=embedding_provider.get_dimension())
    query = MemoryQuery(store, embedding_provider)

    # Execute query
    result = query.query(
        query_text=query_text,
        top_k=top_k,
        source_filter=source,
        chunk_type_filter=chunk_type,
    )

    # Output results
    if output_format == "json":
        click.echo(json.dumps(result.to_dict(), indent=2))
    elif output_format == "markdown":
        click.echo(result.to_markdown())
    else:
        click.echo(str(result))


@memory_cli.command(name="about")
@click.argument("topic")
@click.option(
    "--provider",
    type=click.Choice(["kimi", "ollama", "auto"], case_sensitive=False),
    default="auto",
    help="Embedding provider to use.",
)
@click.option(
    "--model",
    help="Embedding model to use.",
)
@click.option(
    "--top-k",
    type=int,
    default=5,
    help="Number of results to return.",
)
@click.option(
    "--format",
    "output_format",
    type=click.Choice(["text", "markdown"], case_sensitive=False),
    default="text",
    help="Output format.",
)
def query_about(
    topic: str,
    provider: str,
    model: str | None,
    top_k: int,
    output_format: str,
) -> None:
    """Query about a specific topic.

    Shorthand for 'query "What do I know about X?"'

    Examples:
        oclawma memory about Mike
        oclawma memory about "technical setup"
        oclawma memory about boundaries --top-k 10
    """
    # Resolve provider
    if provider == "auto":
        import os

        provider = "kimi" if os.environ.get("KIMI_API_KEY") else "ollama"

    # Create embedding provider
    try:
        embedding_provider = get_embedding_provider(provider, model)
    except ValueError as e:
        raise click.ClickException(str(e)) from e

    # Create store and query interface
    store = VectorMemoryStore(embedding_dimension=embedding_provider.get_dimension())
    query = MemoryQuery(store, embedding_provider)

    # Execute query
    result = query.query_about(topic=topic, top_k=top_k)

    # Output results
    if output_format == "markdown":
        click.echo(result.to_markdown())
    else:
        click.echo(str(result))


@memory_cli.command(name="stats")
def memory_stats() -> None:
    """Show vector memory statistics.

    Examples:
        oclawma memory stats
    """
    store = VectorMemoryStore()
    stats = store.get_stats()

    click.echo("╔══════════════════════════════════════════════════════════╗")
    click.echo("║              VECTOR MEMORY STATISTICS                    ║")
    click.echo("╚══════════════════════════════════════════════════════════╝")
    click.echo()

    click.echo(f"📊 Total Chunks: {stats['total_chunks']}")
    click.echo(f"📁 Database: {stats['db_path']}")
    click.echo(f"📐 Embedding Dimension: {stats['embedding_dimension']}")
    click.echo()

    if stats["by_source"]:
        click.echo("📂 Chunks by Source:")
        for source, count in sorted(stats["by_source"].items()):
            click.echo(f"   {source}: {count}")
        click.echo()

    if stats["by_type"]:
        click.echo("📋 Chunks by Type:")
        for chunk_type, count in sorted(stats["by_type"].items()):
            click.echo(f"   {chunk_type}: {count}")
        click.echo()

    if stats["date_range"] and stats["date_range"]["oldest"]:
        click.echo("📅 Date Range:")
        click.echo(f"   Oldest: {stats['date_range']['oldest']}")
        click.echo(f"   Newest: {stats['date_range']['newest']}")


@memory_cli.command(name="clear")
@click.confirmation_option(
    prompt="Are you sure you want to clear all memory? This cannot be undone!"
)
def clear_memory() -> None:
    """Clear all vector memory.

    WARNING: This deletes all indexed memories permanently!

    Examples:
        oclawma memory clear
    """
    store = VectorMemoryStore()
    store.clear_all()
    click.echo("✓ All vector memory cleared")


@memory_cli.command(name="reindex")
@click.option(
    "--provider",
    type=click.Choice(["kimi", "ollama", "auto"], case_sensitive=False),
    default="auto",
    help="Embedding provider to use.",
)
@click.option(
    "--model",
    help="Embedding model to use.",
)
@click.option(
    "--workspace",
    type=click.Path(exists=True, file_okay=False, path_type=Path),
    default=None,
    help="Path to workspace directory.",
)
def reindex_all(
    provider: str,
    model: str | None,
    workspace: Path | None,
) -> None:
    """Reindex all memory files.

    Clears existing memory and reindexes from scratch.

    Examples:
        oclawma memory reindex
        oclawma memory reindex --provider kimi
    """
    # Clear existing memory
    store = VectorMemoryStore()
    store.clear_all()
    click.echo("✓ Cleared existing memory")

    # Determine paths
    if workspace is None:
        from oclawma.config import get_workspace_dir

        workspace = get_workspace_dir()

    # Resolve provider
    if provider == "auto":
        import os

        if os.environ.get("KIMI_API_KEY"):
            provider = "kimi"
            click.echo("Using Kimi embedding provider (auto-detected)")
        else:
            provider = "ollama"
            click.echo("Using Ollama embedding provider (auto-detected)")

    # Create embedding provider
    try:
        embedding_provider = get_embedding_provider(provider, model)
    except ValueError as e:
        raise click.ClickException(str(e)) from e

    # Create indexer
    indexer = MemoryIndexer()

    total_indexed = 0

    # Index MEMORY.md
    memory_file = workspace / "MEMORY.md"
    if memory_file.exists():
        click.echo(f"Indexing {memory_file}...")
        count = indexer.index_memory_file(memory_file, embedding_provider, store)
        click.echo(f"  Indexed {count} chunks")
        total_indexed += count

    # Index all daily notes
    memory_dir = workspace / "memory"
    if memory_dir.exists():
        for note_file in sorted(memory_dir.glob("20[0-9][0-9]-*.md")):
            click.echo(f"Indexing {note_file.name}...")
            count = indexer.index_memory_file(note_file, embedding_provider, store)
            click.echo(f"  Indexed {count} chunks")
            total_indexed += count

    # Show stats
    stats = store.get_stats()
    click.echo(f"\n✓ Total chunks indexed: {total_indexed}")
    click.echo(f"✓ Total in store: {stats['total_chunks']}")
