import typer
from typing_extensions import Annotated

from pushtunes.utils.cli.commands import push_albums, push_tracks, push_playlist
from pushtunes.utils.cli.commands import compare_albums, compare_tracks, compare_playlist

app = typer.Typer()
push_app = typer.Typer()
compare_app = typer.Typer()

app.add_typer(push_app, name="push")
app.add_typer(compare_app, name="compare")


@push_app.command("albums")
def push_albums_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', or 'csv')")],
    target: Annotated[
        str, typer.Option("--to", help="Target ('spotify', 'ytm' or 'csv')")
    ],
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching (0.0-1.0)"),
    ] = 0.8,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    ytm_auth: Annotated[
        str,
        typer.Option(help="Path to YouTube Music authentication file"),
    ] = "browser.json",
    filter_patterns: Annotated[
        str | None,
        typer.Option(
            "--filter",
            help="Filter patterns for albums/artists (e.g., \"artist:'.*dead.*',album:'.*signal.*'\")",
        ),
    ] = None,
    filter_file: Annotated[
        str | None,
        typer.Option(
            "--filter-from", help="File containing filter patterns (one per line)"
        ),
    ] = None,
    csv_file: Annotated[
        str | None,
        typer.Option(help="Filename of the CSV file to write to or read from"),
    ] = None,
    report: Annotated[
        str | None,
        typer.Option(
            "--report",
            help="Generate detailed report for specific statuses (comma-separated: not_found,filtered,similarity_too_low,already_in_library,added,error)"
        ),
    ] = None,
    color: Annotated[
        bool,
        typer.Option(
            "--color/--no-color",
            help="Enable/disable colored output (default: enabled)"
        ),
    ] = True,
    mappings_file: Annotated[
        str | None,
        typer.Option(
            "--mappings-file",
            help="CSV file containing mappings for albums that can't be matched automatically"
        ),
    ] = None,
    export_csv: Annotated[
        str | None,
        typer.Option(
            "--export-csv",
            help="Export results with specific statuses to CSV (comma-separated: not_found,filtered,similarity_too_low,already_in_library,already_in_library_cache,added,error)"
        ),
    ] = None,
    export_csv_file: Annotated[
        str | None,
        typer.Option(
            "--export-csv-file",
            help="Filename for the exported CSV file (default: albums_export_<statuses>.csv)"
        ),
    ] = None,
):
    """
    Push albums from a source to a target service.
    """
    push_albums(
        source=source,
        target=target,
        similarity=similarity,
        verbose=verbose,
        log_level=log_level,
        ytm_auth=ytm_auth,
        filter_patterns=filter_patterns,
        filter_file=filter_file,
        csv_file=csv_file,
        report=report,
        color=color,
        mappings_file=mappings_file,
        export_csv=export_csv,
        export_csv_file=export_csv_file,
    )


@push_app.command("tracks")
def push_tracks_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', or 'csv')")],
    target: Annotated[
        str, typer.Option("--to", help="Target ('spotify' or 'csv')")
    ],
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching (0.0-1.0)"),
    ] = 0.8,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    filter_patterns: Annotated[
        str | None,
        typer.Option(
            "--filter",
            help="Filter patterns for tracks/artists/albums (e.g., \"artist:'.*dead.*',track:'.*signal.*'\")",
        ),
    ] = None,
    filter_file: Annotated[
        str | None,
        typer.Option(
            "--filter-from", help="File containing filter patterns (one per line)"
        ),
    ] = None,
    csv_file: Annotated[
        str | None,
        typer.Option(help="Filename of the CSV file to write to or read from"),
    ] = None,
    report: Annotated[
        str | None,
        typer.Option(
            "--report",
            help="Generate detailed report for specific statuses (comma-separated: not_found,filtered,similarity_too_low,already_in_library,added,error)"
        ),
    ] = None,
    color: Annotated[
        bool,
        typer.Option(
            "--color/--no-color",
            help="Enable/disable colored output (default: enabled)"
        ),
    ] = True,
    mappings_file: Annotated[
        str | None,
        typer.Option(
            "--mappings-file",
            help="CSV file containing mappings for tracks that can't be matched automatically"
        ),
    ] = None,
    export_csv: Annotated[
        str | None,
        typer.Option(
            "--export-csv",
            help="Export results with specific statuses to CSV (comma-separated: not_found,filtered,similarity_too_low,already_in_library,already_in_library_cache,added,error)"
        ),
    ] = None,
    export_csv_file: Annotated[
        str | None,
        typer.Option(
            "--export-csv-file",
            help="Filename for the exported CSV file (default: tracks_export_<statuses>.csv)"
        ),
    ] = None,
):
    """
    Push tracks from a source to a target service.
    """
    push_tracks(
        source=source,
        target=target,
        similarity=similarity,
        verbose=verbose,
        log_level=log_level,
        filter_patterns=filter_patterns,
        filter_file=filter_file,
        csv_file=csv_file,
        report=report,
        color=color,
        mappings_file=mappings_file,
        export_csv=export_csv,
        export_csv_file=export_csv_file,
    )


@push_app.command("playlist")
def push_playlist_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', 'spotify', 'ytm', or 'csv')")],
    target: Annotated[str, typer.Option("--to", help="Target ('spotify', 'ytm', or 'csv')")],
    playlist_name: Annotated[str | None, typer.Option("--playlist-name", help="Name of the playlist to push (required)")] = None,
    source_playlist_id: Annotated[str | None, typer.Option("--source-playlist-id", help="ID of source playlist (Spotify/YTM only, for direct lookup)")] = None,
    playlist_id: Annotated[str | None, typer.Option("--playlist-id", help="ID of existing playlist on target (Spotify only, for conflict resolution)")] = None,
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching tracks (0.0-1.0)"),
    ] = 0.8,
    require_all_tracks: Annotated[
        bool,
        typer.Option("--require-all-tracks", help="Require all tracks to match (fail if any track can't be matched)"),
    ] = False,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    ytm_auth: Annotated[
        str,
        typer.Option(help="Path to YouTube Music authentication file"),
    ] = "browser.json",
    csv_file: Annotated[
        str | None,
        typer.Option(help="Filename of the CSV file to write to or read from"),
    ] = None,
    on_conflict: Annotated[
        str,
        typer.Option(
            "--on-conflict",
            help="How to handle conflicts: 'abort' (show differences), 'replace' (replace entire playlist), 'append' (add missing tracks), 'sync' (add missing, remove extras)"
        ),
    ] = "abort",
    report: Annotated[
        str | None,
        typer.Option(
            "--report",
            help="Generate detailed report for specific statuses (comma-separated: not_found,matched,similarity_too_low)"
        ),
    ] = None,
    color: Annotated[
        bool,
        typer.Option(
            "--color/--no-color",
            help="Enable/disable colored output (default: enabled)"
        ),
    ] = True,
    mappings_file: Annotated[
        str | None,
        typer.Option(
            "--mappings-file",
            help="CSV file containing mappings for tracks that can't be matched automatically"
        ),
    ] = None,
):
    """
    Push a playlist from a source to a target service, preserving track order.
    """
    push_playlist(
        source=source,
        target=target,
        playlist_name=playlist_name,
        source_playlist_id=source_playlist_id,
        playlist_id=playlist_id,
        similarity=similarity,
        require_all_tracks=require_all_tracks,
        verbose=verbose,
        log_level=log_level,
        ytm_auth=ytm_auth,
        csv_file=csv_file,
        on_conflict=on_conflict,
        report=report,
        color=color,
        mappings_file=mappings_file,
    )


# Compare commands
@compare_app.command("albums")
def compare_albums_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', 'csv', 'spotify', or 'ytm')")],
    target: Annotated[str, typer.Option("--to", help="Target ('subsonic', 'jellyfin', 'csv', 'spotify', or 'ytm')")],
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching (0.0-1.0)"),
    ] = 0.8,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    ytm_auth: Annotated[
        str,
        typer.Option(help="Path to YouTube Music authentication file"),
    ] = "browser.json",
    filter_patterns: Annotated[
        str | None,
        typer.Option(
            "--filter",
            help="Filter patterns for albums/artists (e.g., \"artist:'.*dead.*',album:'.*signal.*'\")",
        ),
    ] = None,
    filter_file: Annotated[
        str | None,
        typer.Option(
            "--filter-from", help="File containing filter patterns (one per line)"
        ),
    ] = None,
    csv_file: Annotated[
        str | None,
        typer.Option(help="Filename of the CSV file to read from (for CSV source/target)"),
    ] = None,
    mappings_file: Annotated[
        str | None,
        typer.Option(
            "--mappings-file",
            help="CSV file containing mappings for albums that can't be matched automatically"
        ),
    ] = None,
    color: Annotated[
        bool,
        typer.Option(
            "--color/--no-color",
            help="Enable/disable colored output (default: enabled)"
        ),
    ] = True,
):
    """
    Compare albums between two sources/services.
    """
    compare_albums(
        source=source,
        target=target,
        similarity=similarity,
        verbose=verbose,
        log_level=log_level,
        ytm_auth=ytm_auth,
        filter_patterns=filter_patterns,
        filter_file=filter_file,
        csv_file=csv_file,
        mappings_file=mappings_file,
        color=color,
    )


@compare_app.command("tracks")
def compare_tracks_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', 'csv', 'spotify', or 'ytm')")],
    target: Annotated[str, typer.Option("--to", help="Target ('subsonic', 'jellyfin', 'csv', 'spotify', or 'ytm')")],
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching (0.0-1.0)"),
    ] = 0.8,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    ytm_auth: Annotated[
        str,
        typer.Option(help="Path to YouTube Music authentication file"),
    ] = "browser.json",
    filter_patterns: Annotated[
        str | None,
        typer.Option(
            "--filter",
            help="Filter patterns for tracks/artists (e.g., \"artist:'.*dead.*',track:'.*signal.*'\")",
        ),
    ] = None,
    filter_file: Annotated[
        str | None,
        typer.Option(
            "--filter-from", help="File containing filter patterns (one per line)"
        ),
    ] = None,
    csv_file: Annotated[
        str | None,
        typer.Option(help="Filename of the CSV file to read from (for CSV source/target)"),
    ] = None,
    mappings_file: Annotated[
        str | None,
        typer.Option(
            "--mappings-file",
            help="CSV file containing mappings for tracks that can't be matched automatically"
        ),
    ] = None,
    color: Annotated[
        bool,
        typer.Option(
            "--color/--no-color",
            help="Enable/disable colored output (default: enabled)"
        ),
    ] = True,
):
    """
    Compare tracks between two sources/services.
    """
    compare_tracks(
        source=source,
        target=target,
        similarity=similarity,
        verbose=verbose,
        log_level=log_level,
        ytm_auth=ytm_auth,
        filter_patterns=filter_patterns,
        filter_file=filter_file,
        csv_file=csv_file,
        mappings_file=mappings_file,
        color=color,
    )


@compare_app.command("playlist")
def compare_playlist_command(
    source: Annotated[str, typer.Option("--from", help="Source ('subsonic', 'jellyfin', 'spotify', or 'ytm')")],
    target: Annotated[str, typer.Option("--to", help="Target ('subsonic', 'jellyfin', 'spotify', or 'ytm')")],
    playlist_name_source: Annotated[
        str,
        typer.Option("--playlist-name", help="Name of the playlist in the source"),
    ],
    playlist_name_target: Annotated[
        str | None,
        typer.Option(
            "--playlist-name-target",
            help="Name of the playlist in the target (defaults to same as source)"
        ),
    ] = None,
    similarity: Annotated[
        float,
        typer.Option(help="Minimum similarity threshold for matching (0.0-1.0)"),
    ] = 0.8,
    verbose: Annotated[
        bool, typer.Option("-v", "--verbose", help="Enable verbose output")
    ] = False,
    log_level: Annotated[
        str,
        typer.Option(
            "--log-level",
            help="Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
        ),
    ] = "INFO",
    ytm_auth: Annotated[
        str,
        typer.Option(help="Path to YouTube Music authentication file"),
    ] = "browser.json",
):
    """
    Compare a playlist between two sources/services.
    """
    compare_playlist(
        source=source,
        target=target,
        playlist_name_source=playlist_name_source,
        playlist_name_target=playlist_name_target,
        similarity=similarity,
        verbose=verbose,
        log_level=log_level,
        ytm_auth=ytm_auth,
    )


if __name__ == "__main__":
    app()
