import argparse
import asyncio
import time
import httpx
import sqlite3
from typing import List, Tuple

async def make_request(client: httpx.AsyncClient, url: str, method: str) -> Tuple[float, bool]:
    """
    Makes a single request to the API endpoint and measures the latency.

    Args:
        client: httpx AsyncClient instance.
        url: The URL of the API endpoint.
        method: The HTTP method to use (e.g., "GET", "POST").

    Returns:
        A tuple containing the latency in seconds and a boolean indicating if the request was successful.
    """
    start_time = time.time()
    try:
        if method.upper() == "GET":
            response = await client.get(url)
        elif method.upper() == "POST":
            response = await client.post(url)
        else:
            raise ValueError(f"Unsupported HTTP method: {method}")

        response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
        latency = time.time() - start_time
        return latency, True
    except httpx.HTTPError as e:
        print(f"HTTP error: {e}")
        return time.time() - start_time, False
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        return time.time() - start_time, False


async def load_test(url: str, method: str, num_requests: int, concurrency: int) -> None:
    """
    Performs a load test against the specified API endpoint.

    Args:
        url: The URL of the API endpoint.
        method: The HTTP method to use.
        num_requests: The total number of requests to make.
        concurrency: The number of concurrent requests to make.
    """
    async with httpx.AsyncClient() as client:
        tasks = [make_request(client, url, method) for _ in range(num_requests)]
        results = await asyncio.gather(*tasks)

    latencies = [latency for latency, success in results if success]
    errors = sum(1 for _, success in results if not success)
    error_rate = (errors / num_requests) * 100 if num_requests > 0 else 0

    if latencies:
        latencies.sort()
        p50 = latencies[len(latencies) // 2]
        p95 = latencies[int(0.95 * len(latencies))]
        p99 = latencies[int(0.99 * len(latencies))]
    else:
        p50, p95, p99 = 0.0, 0.0, 0.0

    print(f"URL: {url}")
    print(f"Method: {method}")
    print(f"Number of requests: {num_requests}")
    print(f"Concurrency: {concurrency}")
    print(f"Error rate: {error_rate:.2f}%")
    print(f"P50 latency: {p50:.4f} seconds")
    print(f"P95 latency: {p95:.4f} seconds")
    print(f"P99 latency: {p99:.4f} seconds")


def main() -> None:
    """
    Main function to parse arguments and run the load test.
    """
    parser = argparse.ArgumentParser(description="API Load Tester")
    parser.add_argument("url", help="The URL of the API endpoint")
    parser.add_argument("method", help="The HTTP method (GET or POST)")
    parser.add_argument("num_requests", type=int, help="The number of requests to make")
    parser.add_argument("concurrency", type=int, help="The number of concurrent requests")

    args = parser.parse_args()

    asyncio.run(load_test(args.url, args.method, args.num_requests, args.concurrency))


if __name__ == "__main__":
    main()