"""Melogen CLI tool."""

from __future__ import annotations

import json
import sys

import click

from melogenai.__version__ import __version__
from melogenai.client import Melogen
from melogenai.exceptions import MelogenError


def _get_client(api_key: str | None, base_url: str | None) -> Melogen:
    kwargs = {}
    if api_key:
        kwargs["api_key"] = api_key
    if base_url:
        kwargs["base_url"] = base_url
    return Melogen(**kwargs)


def _print_json(data: dict) -> None:
    click.echo(json.dumps(data, indent=2, ensure_ascii=False))


@click.group()
@click.version_option(__version__, prog_name="melogen")
@click.option("--api-key", envvar="MELOGEN_API_KEY", help="Melogen API key (or set MELOGEN_API_KEY)")
@click.option("--base-url", envvar="MELOGEN_BASE_URL", help="Override API base URL")
@click.pass_context
def cli(ctx: click.Context, api_key: str | None, base_url: str | None) -> None:
    """Melogen AI - AI-powered music tools."""
    ctx.ensure_object(dict)
    ctx.obj["api_key"] = api_key
    ctx.obj["base_url"] = base_url


@cli.command()
@click.argument("file_url")
@click.option("--format", "-f", "output_formats", multiple=True, help="Output format (midi, musicxml)")
@click.option("--no-midi", is_flag=True, help="Skip MIDI output")
@click.pass_context
def sheet2midi(ctx: click.Context, file_url: str, output_formats: tuple[str, ...], no_midi: bool) -> None:
    """Convert sheet music (PDF/PNG/JPG) to MIDI."""
    try:
        client = _get_client(ctx.obj["api_key"], ctx.obj["base_url"])
        click.echo(f"Submitting {file_url} for conversion...")

        formats = list(output_formats) if output_formats else None
        result = client.sheet2midi.convert(
            file_url, output_formats=formats, convert_midi=not no_midi
        )
        click.echo(f"Task {result.task_id} created. Waiting for completion...")

        final = client.sheet2midi.wait(result.task_id)
        click.echo(f"Status: {final.status}")
        if final.download_urls:
            click.echo("Download URLs:")
            for name, url in final.download_urls.items():
                click.echo(f"  {name}: {url}")
        else:
            _print_json(final.model_dump())
    except MelogenError as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)


@cli.command()
@click.argument("file_url")
@click.option("--stems", is_flag=True, help="Save separated instrument stems")
@click.option("--quantize", is_flag=True, help="Quantize MIDI output to nearest beat")
@click.pass_context
def music2midi(ctx: click.Context, file_url: str, stems: bool, quantize: bool) -> None:
    """Convert audio (MP3/WAV/FLAC/OGG/M4A) to MIDI."""
    try:
        client = _get_client(ctx.obj["api_key"], ctx.obj["base_url"])
        click.echo(f"Submitting {file_url} for conversion...")

        result = client.music2midi.convert(file_url, save_stems=stems, quantize=quantize)
        click.echo(f"Task {result.task_id} created. Waiting for completion...")

        final = client.music2midi.wait(result.task_id)
        click.echo(f"Status: {final.status}")
        if final.download_urls:
            click.echo("Download URLs:")
            for name, url in final.download_urls.items():
                click.echo(f"  {name}: {url}")
        else:
            _print_json(final.model_dump())
    except MelogenError as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)


@cli.command()
@click.option("--mxl", "mxl_file_url", help="URL of a MusicXML (.mxl) file")
@click.option("--image", "image_url", help="URL of a sheet music image")
@click.option("--pdf", "pdf_file_url", help="URL of a PDF score")
@click.option("--lang", default="en", help="Language for analysis (default: en)")
@click.option("--stream/--no-stream", default=True, help="Stream output (default: stream)")
@click.pass_context
def analysis(
    ctx: click.Context,
    mxl_file_url: str | None,
    image_url: str | None,
    pdf_file_url: str | None,
    lang: str,
    stream: bool,
) -> None:
    """Analyze music structure, tonality, harmony, and form."""
    if not any([mxl_file_url, image_url, pdf_file_url]):
        click.echo("Error: provide at least one of --mxl, --image, or --pdf", err=True)
        sys.exit(1)

    try:
        client = _get_client(ctx.obj["api_key"], ctx.obj["base_url"])
        kwargs = {"language": lang}
        if mxl_file_url:
            kwargs["mxl_file_url"] = mxl_file_url
        if image_url:
            kwargs["image_url"] = image_url
        if pdf_file_url:
            kwargs["pdf_file_url"] = pdf_file_url

        if stream:
            for chunk in client.analysis.analyze_stream(**kwargs):
                click.echo(chunk, nl=False)
            click.echo()
        else:
            result = client.analysis.analyze(**kwargs)
            click.echo(result.analysis)
    except MelogenError as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)


@cli.group()
def auth() -> None:
    """Authentication commands."""


@auth.command()
@click.pass_context
def verify(ctx: click.Context) -> None:
    """Verify your API key is valid."""
    try:
        client = _get_client(ctx.obj["api_key"], ctx.obj["base_url"])
        token_data = client._auth.get_token(client._config.api_key)
        click.echo(f"API key is valid. User ID: {token_data['user_id']}")
        if token_data.get("scopes"):
            click.echo(f"Scopes: {', '.join(token_data['scopes'])}")
    except MelogenError as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)
