from __future__ import annotations

import asyncio
import argparse
import sys
import threading
from pathlib import Path

from .downloader import Downloader
from .models import DownloadConfig, DownloadProgress, RetryPolicy, DownloadTask


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Thread downloader with range fallback")
    parser.add_argument("url", help="File URL")
    parser.add_argument("output", help="Output file path")
    parser.add_argument("--workers", type=int, default=4, help="Number of segment workers")
    parser.add_argument("--chunk-size", type=int, default=1024 * 256, help="Chunk size in bytes")
    parser.add_argument("--timeout", type=float, default=30.0, help="Request timeout in seconds")
    parser.add_argument("--retries", type=int, default=3, help="Maximum retry attempts")
    parser.add_argument("--global-limit", type=int, default=4, help="Global downloader concurrency limit")
    parser.add_argument(
        "--mem-assemble",
        choices=["yes", "no"],
        default="yes",
        help="Assemble mode: yes (memory) or no (temp files)",
    )
    return parser


def main() -> int:
    parser = build_parser()
    args = parser.parse_args()

    retry_policy = RetryPolicy(max_attempts=max(1, args.retries))
    config = DownloadConfig(
        workers=max(1, args.workers),
        chunk_size=max(1, args.chunk_size),
        timeout_seconds=max(0.1, args.timeout),
        retry_policy=retry_policy,
        mem_assemble=args.mem_assemble,  # type: ignore
    )

    Downloader.set_global_concurrency_limit(max(1, args.global_limit))
    downloader = Downloader(config=config)

    progress_lock = threading.Lock()

    def on_progress(progress: DownloadProgress) -> None:
        with progress_lock:
            if progress.total_bytes:
                percent = progress.percent or 0.0
                text = (
                    f"\\r[{progress.mode}] {progress.downloaded_bytes}/{progress.total_bytes} bytes "
                    f"({percent:6.2f}%) workers={progress.worker_count}"
                )
            else:
                text = f"\\r[{progress.mode}] {progress.downloaded_bytes} bytes workers={progress.worker_count}"
            sys.stdout.write(text)
            sys.stdout.flush()

    try:
        task = DownloadTask(args.url, str(Path(args.output)))
        result = asyncio.run(
            downloader.download(
                task=task,
                progress_callback=on_progress,
            )
        )
    except Exception as exc:
        sys.stdout.write("\n")
        sys.stderr.write(f"Download failed: {exc}\n")
        return 1

    sys.stdout.write("\n")
    sys.stdout.write(
        f"Done. bytes={result.bytes_written} mode={'multi' if result.used_multi_thread else 'single'} "
        f"range_supported={result.range_supported}\n"
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
