import os
import webbrowser
from pathlib import Path
from threading import Timer

import click

from pixel_patrol_base.api import (
    create_project,
    add_paths,
    set_settings,
    process_files,
    export_project,
    import_project,
    show_report,
)
from pixel_patrol_base.core.project_settings import Settings


@click.group()
def cli():
    """
    A command-line tool for processing image reports with Pixel Patrol.

    This tool facilitates a two-step process:
    1. Exporting a processed project to a ZIP file.
    2. Displaying a report from an exported ZIP file.
    """
    pass

@cli.command()
@click.argument('base_directory', type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True, path_type=Path))
@click.option('--output-zip', '-o', type=click.Path(exists=False, dir_okay=False, writable=True, path_type=Path),
              help='Required: Name of the output ZIP file for the exported project (e.g., my_project.zip).',
              required=True)
@click.option('--name', type=str, required=False,
              help='Optional: Name of the project. If not provided, derived from BASE_DIRECTORY.')
@click.option('--paths', '-p', multiple=True, type=str,
              help='Optional: Paths (subdirectories) to treat as **experimental conditions**, relative to BASE_DIRECTORY. '
                   'Can be specified multiple times. If omitted, all immediate subdirectories '
                   'of BASE_DIRECTORY will be included, or if BASE_DIRECTORY has no subdirectories, '
                   'it is treated as a single condition.')
@click.option('--loader', '-l', type=str, show_default=True,
              help='Recommended: Pixel Patrol file loader (e.g., bioio, zarr). If omitted, only basic file info is collected.')
@click.option('--cmap', type=str, default="rainbow", show_default=True,
              help='Colormap for report visualization (e.g., viridis, plasma, rainbow).')
@click.option('--n-example-files', type=int, default=9, show_default=True,
              help='Number of example files to display in the report.')
@click.option('--file-extension', '-e', multiple=True,
              help='Optional: File extensions to include (e.g., png, jpg). Can be specified multiple times. '
                   'If not specified, all supported extensions will be used.')
@click.option('--flavor', type=str, default="", show_default=True,
              help='Name of pixel patrol configuration, will be displayed next to the tool name.')
def export(base_directory: Path, output_zip: Path, name: str | None, paths: tuple[str, ...],
           loader: str, cmap: str, n_example_files: int, file_extension: tuple[str, ...], flavor: str):
    """
    Exports a Pixel Patrol project to a ZIP file.
    Processes images from the BASE_DIRECTORY and specified --paths.
    """
    # Always operate on an absolute base directory so downstream path resolution is stable.
    base_directory = base_directory.resolve()

    # Derive project_name if not provided
    if name is None:
        name = base_directory.name # Use the name of the base directory
        click.echo(f"Project name not provided, deriving from base directory: '{name}'")

    click.echo(f"Creating project: '{name}' from base directory '{base_directory}'")
    my_project = create_project(name, str(base_directory), loader=loader) # Assuming create_project takes string path

    if paths:
        click.echo(f"Adding explicitly specified paths: {', '.join(paths)}. Resolution will be relative to '{base_directory}'")
        add_paths(my_project, paths)
    else:
        # If no paths, we want to add the base directory itself.
        click.echo(f"No --paths specified. Processing all images in '{base_directory}'.")
        add_paths(my_project, base_directory)

    selected_extensions = set(file_extension) if file_extension else "all"
    initial_settings = Settings(
        cmap=cmap,
        n_example_files=n_example_files,
        selected_file_extensions=selected_extensions,
        pixel_patrol_flavor=flavor
    )
    click.echo(f"Setting project settings: {initial_settings}")
    set_settings(my_project, initial_settings)

    click.echo("Processing images...")
    process_files(my_project)

    click.echo(f"Exporting project to: '{output_zip}'")
    export_project(my_project, Path(output_zip)) # Assuming export_project takes string path
    click.echo("Export complete.")


@cli.command()
@click.argument('input_zip', type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path))
@click.option('--port', type=int, default=8050, show_default=True,
              help='Port number for the Dash report server.')
def report(input_zip: Path, port: int):
    """
    Displays the report of an exported Pixel Patrol project from a ZIP file.
    """
    click.echo(f"Importing project from: '{input_zip}'")
    my_project = import_project(Path(input_zip))
    click.echo("Project imported.")

    report_url = f"http://127.0.0.1:{port}"
    click.echo(f"Dash report will run on {report_url}/")
    click.echo("Attempting to open report in your default browser...")

    # We don't need a Timer here if show_report is blocking and we open BEFORE
    # However, in some systems, opening too fast can fail. A small delay is safer.
    def _open_browser():
        # This check is still useful if Werkzeug debug mode spawns a second process
        # and you want to ensure it only opens once from the parent.
        if not os.environ.get("WERKZEUG_RUN_MAIN"):
            webbrowser.open_new_tab(report_url)

    # Schedule the browser open for slightly in the future to give the OS a moment
    # and to potentially allow Dash's own startup messages to appear first.
    Timer(1, _open_browser).start() # 0.5 seconds delay

    click.echo("Showing report...")
    # Pass the port to show_report. You must ensure show_report accepts this.
    show_report(my_project, port=port)

if __name__ == '__main__':
    cli()
