"""Command-line interface for pretok."""

from __future__ import annotations

import argparse
import json
import sys
from typing import TextIO


def create_parser() -> argparse.ArgumentParser:
    """Create the argument parser for pretok CLI."""
    parser = argparse.ArgumentParser(
        prog="pretok",
        description="Universal pre-token language adaptation layer for text-based LLMs.",
        epilog="For more information, see: https://github.com/yen0304/pretok",
    )
    parser.add_argument(
        "--version",
        action="version",
        version=f"%(prog)s {_get_version()}",
    )

    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # --- process command ---
    process_parser = subparsers.add_parser(
        "process",
        help="Process text through the pretok pipeline",
    )
    process_parser.add_argument(
        "text",
        nargs="?",
        help="Text to process (reads from stdin if omitted)",
    )
    process_parser.add_argument(
        "-t", "--target",
        default="en",
        help="Target language code (default: en)",
    )
    process_parser.add_argument(
        "--detect-only",
        action="store_true",
        help="Only detect languages, don't translate",
    )
    process_parser.add_argument(
        "--no-translate",
        action="store_true",
        help="Skip translation",
    )
    process_parser.add_argument(
        "-c", "--config",
        help="Path to configuration file",
    )
    process_parser.add_argument(
        "-m", "--model-id",
        help="Model ID for capability lookup",
    )
    process_parser.add_argument(
        "--json",
        action="store_true",
        dest="json_output",
        help="Output as JSON",
    )

    # --- detect command ---
    detect_parser = subparsers.add_parser(
        "detect",
        help="Detect the language of text",
    )
    detect_parser.add_argument(
        "text",
        nargs="?",
        help="Text to detect (reads from stdin if omitted)",
    )
    detect_parser.add_argument(
        "--backend",
        default="langdetect",
        choices=["langdetect", "fasttext"],
        help="Detection backend (default: langdetect)",
    )
    detect_parser.add_argument(
        "--json",
        action="store_true",
        dest="json_output",
        help="Output as JSON",
    )

    # --- segment command ---
    segment_parser = subparsers.add_parser(
        "segment",
        help="Parse text into segments",
    )
    segment_parser.add_argument(
        "text",
        nargs="?",
        help="Text to segment (reads from stdin if omitted)",
    )
    segment_parser.add_argument(
        "-f", "--format",
        choices=["chatml", "llama", "llama2", "alpaca", "vicuna", "mistral"],
        help="Force specific prompt format",
    )
    segment_parser.add_argument(
        "--json",
        action="store_true",
        dest="json_output",
        help="Output as JSON",
    )

    # --- config command ---
    config_parser = subparsers.add_parser(
        "config",
        help="Show or validate configuration",
    )
    config_parser.add_argument(
        "action",
        choices=["show", "validate"],
        help="Action to perform",
    )
    config_parser.add_argument(
        "-c", "--config",
        help="Path to configuration file",
    )

    return parser


def _get_version() -> str:
    """Get pretok version string."""
    from pretok._version import __version__

    return __version__


def _read_text(text: str | None, stdin: TextIO = sys.stdin) -> str:
    """Read text from argument or stdin.

    Args:
        text: Text from command line argument
        stdin: Standard input stream

    Returns:
        Text string
    """
    if text is not None:
        return text

    if not stdin.isatty():
        return stdin.read().rstrip("\n")

    print("Enter text (Ctrl+D to finish):", file=sys.stderr)
    return stdin.read().rstrip("\n")


def cmd_process(args: argparse.Namespace) -> int:
    """Handle the process command."""
    from pretok.config import load_config
    from pretok.pipeline.core import Pretok

    text = _read_text(args.text)
    if not text:
        print("Error: no text provided", file=sys.stderr)
        return 1

    config = None
    if args.config:
        config = load_config(args.config)

    pretok = Pretok(
        config=config,
        target_language=args.target,
        model_id=args.model_id,
    )

    result = pretok.process(
        text,
        detect_only=args.detect_only,
        translate=not args.no_translate,
    )

    if args.json_output:
        output = {
            "original_text": result.original_text,
            "processed_text": result.processed_text,
            "was_modified": result.was_modified,
            "from_cache": result.from_cache,
            "detections": [
                {
                    "language": d.language,
                    "confidence": d.confidence,
                    "detector": d.detector,
                }
                for d in result.detections
            ],
            "translations": [
                {
                    "source_text": t.source_text,
                    "translated_text": t.translated_text,
                    "source_language": t.source_language,
                    "target_language": t.target_language,
                }
                for t in result.translations
            ],
            "stats": {
                "total_segments": result.stats.total_segments,
                "translated_segments": result.stats.translated_segments,
                "detection_time_ms": round(result.stats.detection_time_ms, 2),
                "translation_time_ms": round(result.stats.translation_time_ms, 2),
                "total_time_ms": round(result.stats.total_time_ms, 2),
            },
        }
        print(json.dumps(output, ensure_ascii=False, indent=2))
    else:
        print(result.processed_text)

    return 0


def cmd_detect(args: argparse.Namespace) -> int:
    """Handle the detect command."""
    from pretok.detection.composite import create_detector

    text = _read_text(args.text)
    if not text:
        print("Error: no text provided", file=sys.stderr)
        return 1

    detector = create_detector(args.backend)
    result = detector.detect(text)

    if args.json_output:
        output = {
            "language": result.language,
            "confidence": result.confidence,
            "detector": result.detector,
        }
        print(json.dumps(output, ensure_ascii=False, indent=2))
    else:
        print(f"{result.language} (confidence: {result.confidence:.2f})")

    return 0


def cmd_segment(args: argparse.Namespace) -> int:
    """Handle the segment command."""
    from pretok.segment import lex_prompt

    text = _read_text(args.text)
    if not text:
        print("Error: no text provided", file=sys.stderr)
        return 1

    segments = lex_prompt(text, format_hint=args.format)

    if args.json_output:
        output = [
            {
                "type": seg.type.name,
                "content": seg.content,
                "start": seg.start,
                "end": seg.end,
                "translatable": seg.translatable,
            }
            for seg in segments
        ]
        print(json.dumps(output, ensure_ascii=False, indent=2))
    else:
        for i, seg in enumerate(segments):
            print(f"[{i}] {seg.type.name}: {seg.content!r}")

    return 0


def cmd_config(args: argparse.Namespace) -> int:
    """Handle the config command."""
    from pretok.config import ConfigurationError, get_default_config, load_config

    if args.action == "show":
        if args.config:
            try:
                config = load_config(args.config)
            except ConfigurationError as e:
                print(f"Error loading config: {e}", file=sys.stderr)
                return 1
        else:
            config = get_default_config()

        print(json.dumps(config.to_dict(), ensure_ascii=False, indent=2))
        return 0

    elif args.action == "validate":
        if not args.config:
            print("Error: --config is required for validate", file=sys.stderr)
            return 1

        try:
            load_config(args.config)
            print("✓ Configuration is valid")
            return 0
        except ConfigurationError as e:
            print(f"✗ Configuration error: {e}", file=sys.stderr)
            return 1

    return 0


def main(argv: list[str] | None = None) -> int:
    """Main entry point for pretok CLI.

    Args:
        argv: Command line arguments (uses sys.argv if None)

    Returns:
        Exit code
    """
    parser = create_parser()
    args = parser.parse_args(argv)

    if not args.command:
        parser.print_help()
        return 0

    commands = {
        "process": cmd_process,
        "detect": cmd_detect,
        "segment": cmd_segment,
        "config": cmd_config,
    }

    handler = commands.get(args.command)
    if handler:
        try:
            return handler(args)
        except KeyboardInterrupt:
            print("\nInterrupted", file=sys.stderr)
            return 130
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)
            return 1

    parser.print_help()
    return 0


if __name__ == "__main__":
    sys.exit(main())
