import asyncio
import json
import os
import re
import subprocess
from urllib.parse import unquote, urlparse

import aiohttp

# ==== НАСТРОЙКИ ====
BASE_URL = "https://readzy.io"
OUTPUT_DIR = input("Введите название папки: ")
MAX_CONCURRENT_DOWNLOADS = 20
MAX_RETRIES = 3
REQUEST_TIMEOUT = aiohttp.ClientTimeout(total=60, connect=15)
# ===================

os.makedirs(OUTPUT_DIR, exist_ok=True)


def load_json_data():
    source = input(
        "JSON: [Enter] file.txt, [c] буфер обмена, [p] вставить сюда: "
    ).strip().lower()

    if source == "c":
        result = subprocess.run(
            ["powershell", "-NoProfile", "-Command", "Get-Clipboard -Raw"],
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
            check=True,
        )
        return json.loads(result.stdout)

    if source == "p":
        print("Вставьте многострочный JSON. Для завершения введите END отдельной строкой:")
        lines = []
        while True:
            line = input()
            if line.strip() == "END":
                break
            lines.append(line)
        return json.loads("\n".join(lines))

    with open("file.txt", "r", encoding="utf-8") as file:
        return json.load(file)


data = load_json_data()

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Referer": BASE_URL + "/",
}

def build_download_info(item, index):
    url_path = item["url"]

    # Собираем полный URL к прокси
    if url_path.startswith("http"):
        proxy_url = url_path
    else:
        proxy_url = BASE_URL + url_path

    # Достаём оригинальный URL из параметра url=
    m = re.search(r"[?&]url=([^&]+)", url_path)
    if m:
        original_url = unquote(m.group(1))
    else:
        original_url = proxy_url

    # Имя файла из оригинального URL
    parsed = urlparse(original_url)
    filename = os.path.basename(parsed.path) or f"image_{i}.webp"

    # На случай коллизии — префикс с индексом
    extension = os.path.splitext(filename)[1] or ".webp"
    filename = f"src_{index:03d}{extension}"
    filepath = os.path.join(OUTPUT_DIR, filename)
    return proxy_url, filename, filepath


async def download_one(session, semaphore, item, index):
    proxy_url, filename, filepath = build_download_info(item, index)
    temporary_path = filepath + ".part"

    async with semaphore:
        for attempt in range(1, MAX_RETRIES + 1):
            try:
                async with session.get(proxy_url) as response:
                    response.raise_for_status()
                    size = 0
                    with open(temporary_path, "wb") as output:
                        async for chunk in response.content.iter_chunked(1024 * 128):
                            output.write(chunk)
                            size += len(chunk)
                    os.replace(temporary_path, filepath)
                    print(f"[OK] {filename}  ({size} bytes)")
                    return
            except (aiohttp.ClientError, asyncio.TimeoutError, OSError) as error:
                if os.path.exists(temporary_path):
                    os.remove(temporary_path)
                if attempt == MAX_RETRIES:
                    print(f"[FAIL] {proxy_url} -> {error}")
                    return
                await asyncio.sleep(2 ** (attempt - 1))


async def main():
    connector = aiohttp.TCPConnector(limit=MAX_CONCURRENT_DOWNLOADS)
    semaphore = asyncio.Semaphore(MAX_CONCURRENT_DOWNLOADS)
    async with aiohttp.ClientSession(
        headers=HEADERS,
        timeout=REQUEST_TIMEOUT,
        connector=connector,
    ) as session:
        tasks = [
            download_one(session, semaphore, item, index)
            for index, item in enumerate(data, start=1)
        ]
        await asyncio.gather(*tasks)


if __name__ == "__main__":
    asyncio.run(main())
    print("Готово.")