from collections import defaultdict
import os 
import shutil
import typer
from rich.console import Console
from rich.progress import Progress,BarColumn, TextColumn, TimeElapsedColumn
from utils import (
    resolve_path,
    group_files_by_extension,
    map_ext_to_dir,
    display_summary_table,
    is_unique_dir_name_and_not_empty,
)
from raw import group_fuzzy_files, generate_cluster_names
from src.semantic import (
    group_files_by_extension_content,
    embed_and_for_cluster_by_ext,
    get_missing_ollama_models,
    pull_ollama_model,
)
from collections import deque
from pathlib import Path




app = typer.Typer()
console = Console()



def eliminate_duplicates():
    pass



def semantic_grouping():
    pass



def fuzzing_grouping():
    pass




@app.command()
def organize_files(
    is_interactive: bool = typer.Option(
        False, "--interactive", "-i",
        help="Run in interactive mode"
    ),
    src:str = typer.Option(
        os.getcwd(),
        "--dir", "-d",
        help="Which dir files you want to arrange"
    ),
    recursive:bool = typer.Option(
        False,"--recursive","-r",
        help="Organize files in subdirectories recursively"
    ),
    raw:bool = typer.Option(
        True,"--raw","-R",
        help="Organize files without grouping them into clusters based on name similarity"
    ),
    semantic:bool = typer.Option(
        False,"--semantic","-s",
        help="Organize files based on semantic similarity using NLP techniques"
    ),
    preview:bool = typer.Option(
        False,"--preview","-p",
        help="Preview the files to be organized"
    ),
    eliminate_duplicates:bool = typer.Option(
        False,"--ed","--eliminate-duplicates",
        help = "Eliminate Duplicates"
    )
):
    src = resolve_path(src)
    files = group_files_by_extension(src)
    dir_names = map_ext_to_dir(files)
    display_summary_table(dir_names)
    clusters = []
    if preview:
        clusters = group_fuzzy_files(dir_names)
        console.print(clusters)
        return
    
    if semantic:
        console.print("[cyan]Starting semantic analysis...[/cyan]")

        required_models = ["embeddinggemma", "llama3.2"]
        try:
            missing_models = get_missing_ollama_models(required_models)
        except RuntimeError as e:
            console.print(f"[red]{e}[/red]")
            console.print("[yellow]Ensure Ollama is installed and running, then try again.[/yellow]")
            return

        if missing_models:
            console.print(f"[yellow]Missing Ollama models:[/yellow] {', '.join(missing_models)}")
            should_pull = typer.confirm("Pull missing models now?", default=True)
            if not should_pull:
                console.print("[yellow]Semantic mode cancelled. Please pull models manually and retry.[/yellow]")
                return

            for model in missing_models:
                console.print(f"[cyan]Pulling model: {model}...[/cyan]")
                try:
                    pull_ollama_model(model)
                    console.print(f"[green]✓ Pulled {model}[/green]")
                except Exception as e:
                    console.print(f"[red]Failed pulling {model}: {e}[/red]")
                    return

        title_embeddings, content_embeddings = group_files_by_extension_content(src)
        if not title_embeddings:
            console.print("[yellow]No files found to process semantically[/yellow]")
            return
        
        console.print(f"[green]✓ Successfully embedded {len(title_embeddings)} files[/green]")
        console.print("[cyan]Clustering files by semantic similarity...[/cyan]")
        
        clusters = embed_and_for_cluster_by_ext(title_embeddings, content_embeddings, dir_names)
        
        console.print("\n[bold green]Semantic Clustering Results:[/bold green]")
        for cluster_id, cluster_info in enumerate(clusters, 1):
            if cluster_info:
                console.print(f"\n[magenta]Cluster {cluster_id}:[/magenta]")
                console.print(cluster_info)
        
        return

    if raw:
        clusters_dict = group_fuzzy_files(dir_names)
        grouped_files = defaultdict(list)
        for dir_name,files_clusters in clusters_dict.items():
            for file_cluster in files_clusters:
                if len(file_cluster) == 1:
                    grouped_files[dir_name].extend(file_cluster)
                    continue
                cluster_name = generate_cluster_names(file_cluster)
                grouped_files[cluster_name].append(file_cluster)
        console.print(grouped_files)
        return 


    if recursive:
        whole_map = dict()

        queue = deque([Path(src)])

        while queue:
            src:Path = queue.popleft()
            for dirs in src.iterdir():
                if dirs.is_dir():

                    queue.append(dirs)

        
    if eliminate_duplicates:
        pass

    total_files = sum(len(files) for files in dir_names.values())
    
    with Progress(
        TextColumn("[progress.description]{task.description}"),
        BarColumn(),
        TextColumn("[progress.percentage]{task.percentage:>3.1f}%"),
        TimeElapsedColumn(),
        console=console,
    ) as progress:
        task = progress.add_task(f"[cyan]Moving files...", total=total_files)
        
        for f_dir, f_list in dir_names.items():
            dir_name = f_dir
            if is_interactive:
                dir_name = typer.prompt(f"Enter dir name of your choice for ext: {dir_name} Default is: {dir_name}")
                dir_name = is_unique_dir_name_and_not_empty(dir_name)
            dst_path = src / dir_name
            if dst_path.exists():
                choice = typer.confirm(f"Dir:{dir_name} already exists push all files here(y/N) or choose different name")
                if not choice:
                    dir_name = typer.prompt(f"Enter dir name of your choice for ext: {dir_name} Default is: {dir_name}")
                    dir_name = is_unique_dir_name_and_not_empty(dir_name)
                    dst_path = src / dir_name
            dst_path.mkdir(exist_ok=True)
            for f in f_list:
                try:
                    progress.update(task, description=f"[cyan]Moving: {f[:30]}")
                    shutil.move(src/f, dst_path/f)
                except Exception as e:
                    console.print(f"[red]Error moving {f}: {str(e)}[/red]")
                progress.advance(task)
        
        console.print(f"[green]✓ Successfully moved {total_files} files[/green]")





if __name__ == "__main__":
    app()