"""Click-based CLI tool for the Qwen3-TTS service.

Communicates with the FastAPI server running at http://localhost:9100.

Usage:
    python cli.py voice list
    python cli.py voice clone narrator_morgan ./sample.wav --ref-text "transcript"
    python cli.py voice design young_hero --instruct "Male, 17, nervous tenor"
    python cli.py voice delete old_voice
    python cli.py speak "Hello world" --voice narrator_morgan -o hello.wav
    python cli.py builtin "Hello world" --speaker Ryan --instruct "cheerful" -o hello.wav
    python cli.py dialog script.txt -o scene.wav --pause 500
"""

from __future__ import annotations

import sys
from pathlib import Path

import click
import httpx

BASE_URL = "http://localhost:9100"
TIMEOUT = 300.0  # TTS generation can be slow


def _client() -> httpx.Client:
    return httpx.Client(base_url=BASE_URL, timeout=TIMEOUT)


def _die(msg: str) -> None:
    click.echo(f"Error: {msg}", err=True)
    sys.exit(1)


def _check_response(r: httpx.Response) -> None:
    if r.status_code >= 400:
        try:
            detail = r.json().get("detail", r.text)
        except Exception:
            detail = r.text
        _die(f"[{r.status_code}] {detail}")


# ── Root group ──────────────────────────────────────────────────────


@click.group()
def cli() -> None:
    """Qwen3-TTS command-line tool."""


# ── Voice management ────────────────────────────────────────────────


@cli.group()
def voice() -> None:
    """Manage voice profiles."""


@voice.command("list")
def voice_list() -> None:
    """List all saved voice profiles."""
    with _client() as c:
        r = c.get("/voices")
        _check_response(r)
    voices = r.json()
    if not voices:
        click.echo("No voice profiles found.")
        return
    for v in voices:
        click.echo(f"  {v['name']:20s}  type={v['type']:6s}  lang={v['language']}")
        if v.get("description"):
            click.echo(f"  {'':20s}  {v['description']}")


@voice.command("clone")
@click.argument("name")
@click.argument("audio_file", type=click.Path(exists=True))
@click.option("--ref-text", required=True, help="Transcript of the reference audio")
@click.option("--language", default="Auto", help="Language code (default: Auto)")
def voice_clone(name: str, audio_file: str, ref_text: str, language: str) -> None:
    """Create a voice profile by cloning from an audio file."""
    path = Path(audio_file)
    with _client() as c:
        r = c.post(
            "/voices/clone",
            data={"name": name, "ref_text": ref_text, "language": language},
            files={"file": (path.name, path.read_bytes(), "audio/wav")},
        )
        _check_response(r)
    click.echo(f"Created voice profile: {name}")


@voice.command("design")
@click.argument("name")
@click.option("--instruct", required=True, help="Text description of the voice")
@click.option("--sample-text", default="Hello, how are you today?",
              help="Text for the voice sample")
@click.option("--language", default="English", help="Language (default: English)")
def voice_design(name: str, instruct: str, sample_text: str, language: str) -> None:
    """Create a voice profile from a text description."""
    with _client() as c:
        r = c.post("/voices/design", json={
            "name": name,
            "instruct": instruct,
            "sample_text": sample_text,
            "language": language,
        })
        _check_response(r)
    click.echo(f"Created voice profile: {name}")


@voice.command("delete")
@click.argument("name")
def voice_delete(name: str) -> None:
    """Delete a voice profile."""
    with _client() as c:
        r = c.delete(f"/voices/{name}")
        _check_response(r)
    click.echo(f"Deleted voice profile: {name}")


# ── Speech generation ───────────────────────────────────────────────


@cli.command()
@click.argument("text")
@click.option("--voice", "voice_name", required=True, help="Saved voice profile name")
@click.option("-o", "--output", required=True, type=click.Path(), help="Output WAV path")
@click.option("--language", default="Auto", help="Language (default: Auto)")
def speak(text: str, voice_name: str, output: str, language: str) -> None:
    """Generate speech with a saved voice profile."""
    with _client() as c:
        r = c.post("/tts/generate", json={
            "text": text,
            "voice": voice_name,
            "language": language,
        })
        _check_response(r)
    Path(output).write_bytes(r.content)
    click.echo(f"Saved to {output}")


@cli.command()
@click.argument("text")
@click.option("--speaker", default="Ryan", help="Built-in speaker name")
@click.option("--instruct", default="", help="Style/emotion instruction")
@click.option("-o", "--output", required=True, type=click.Path(), help="Output WAV path")
@click.option("--language", default="English", help="Language (default: English)")
def builtin(text: str, speaker: str, instruct: str, output: str, language: str) -> None:
    """Generate speech with a built-in speaker."""
    with _client() as c:
        r = c.post("/tts/custom", json={
            "text": text,
            "speaker": speaker,
            "instruct": instruct,
            "language": language,
        })
        _check_response(r)
    Path(output).write_bytes(r.content)
    click.echo(f"Saved to {output}")


# ── Dialog ──────────────────────────────────────────────────────────


@cli.command()
@click.argument("script_file", type=click.Path(exists=True))
@click.option("-o", "--output", required=True, type=click.Path(), help="Output WAV path")
@click.option("--pause", default=500, type=int, help="Default pause between lines (ms)")
def dialog(script_file: str, output: str, pause: int) -> None:
    """Generate multi-character dialog from a script file."""
    # Parse the script file locally, then send structured lines to the API
    from dialog import parse_script  # noqa: avoid import at top level for CLI-only deps

    script_text = Path(script_file).read_text()
    lines = parse_script(script_text, default_pause_ms=pause)
    if not lines:
        _die("No valid dialog lines found in script")

    with _client() as c:
        r = c.post("/tts/dialog", json={
            "lines": [l.model_dump() for l in lines],
            "default_pause_ms": pause,
        })
        _check_response(r)
    Path(output).write_bytes(r.content)
    click.echo(f"Saved to {output}")


if __name__ == "__main__":
    cli()
