import argparse
import asyncio
import sys
from pathlib import Path
from typing import Optional

import pyperclip

from narrate_gpt.llm import LiteLLM
from narrate_gpt.text import clean_text as local_clean_text
from narrate_gpt.tts import AudioFormat, load_tts


def make_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="narrate-gpt",
        description="Convert text to speech using OpenAI's TTS API",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    # Add arguments
    parser.add_argument(
        "text",
        nargs="?",
        help="Text to convert to speech. If not provided, will read from clipboard if -c is set",
    )
    parser.add_argument(
        "-c",
        "--clipboard",
        action="store_true",
        help="Read text from clipboard instead of command line",
    )
    parser.add_argument(
        "-f",
        "--audio-format",
        dest="audio_format",
        type=AudioFormat,
        help="Audio output format",
        choices=[f.value for f in AudioFormat],
        default=None,
    )
    parser.add_argument(
        "-o",
        "--output",
        help="Output file path. If not provided, will play audio directly",
        type=Path,
        default=None,
    )
    parser.add_argument(
        "-t",
        "--tts-provider",
        type=str,
        help="TTS provider to use",
        default=None,
    )
    parser.add_argument(
        "-m",
        "--tts-model",
        type=str,
        help="TTS model to use",
        default=None,
    )
    parser.add_argument(
        "-v",
        "--tts-voice",
        type=str,
        help="Voice to use for speech",
        default=None,
    )
    parser.add_argument(
        "--no-clean",
        action="store_false",
        dest="clean",
        help="Disable basic cleanup (HTML tags and clipboard artifacts)",
    )
    parser.add_argument(
        "--no-format",
        action="store_false",
        dest="format_text",
        help="Disable transcript formatting (enabled by default)",
    )
    parser.add_argument(
        "-l",
        "--llm-model",
        type=str,
        help="LLM model to use for transcript formatting",
        default=None,
    )
    parser.set_defaults(clean=True, format_text=True)
    return parser


async def generate_audio(
    text: Optional[str] = None,
    clipboard: bool = False,
    output: Optional[Path] = None,
    audio_format: Optional[AudioFormat] = None,
    tts_provider: Optional[str] = None,
    tts_model: Optional[str] = None,
    tts_voice: Optional[str] = None,
    clean: bool = True,
    format_text: bool = True,
    llm_model: Optional[str] = None,
) -> None:
    # Get text from clipboard if requested
    if clipboard:
        text = pyperclip.paste()
        if not text:
            raise ValueError("Clipboard is empty")

    if text is None:
        raise ValueError("No text provided")

    # Create TTS client
    tts = load_tts(tts_provider)

    if clean:
        text = local_clean_text(text)

    if format_text:
        print(f"Formatting text with LLM model: {llm_model}")
        llm = LiteLLM()
        text = await llm.format_text(text, model=llm_model)

    print(f"Generating audio with TTS model: {tts_model}")
    if output:
        await tts.save(
            text=text,
            path=str(output),
            model=tts_model,
            voice=tts_voice,
            format=audio_format,
        )
        print(f"Audio saved to: {output}")
    else:
        await tts.play(
            text=text,
            model=tts_model,
            voice=tts_voice,
        )


def main():
    parser = make_parser()
    args = parser.parse_args()

    if (args.text and args.clipboard) or (not args.text and not args.clipboard):
        parser.print_help()
        sys.exit(1)

    try:
        asyncio.run(generate_audio(**vars(args)))
        sys.exit(0)
    except Exception as e:
        print(f"Error: {str(e)}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
