import concurrent.futures
import json
import statistics
import sys
import time
from urllib.request import HTTPRedirectHandler, Request, build_opener

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

OPENER = build_opener(NoRedirect)

BASE = sys.argv[1] if len(sys.argv) > 1 else 'http://127.0.0.1:8000'
REQUESTS_PER_ENDPOINT = int(sys.argv[2]) if len(sys.argv) > 2 else 300
CONCURRENCY = int(sys.argv[3]) if len(sys.argv) > 3 else 30
ENDPOINTS = ['/clinic/login', '/admin/login', '/clinic/dashboard', '/appointments', '/patients']

def hit(path):
    started = time.perf_counter()
    try:
        request = Request(BASE + path, headers={'Accept': 'text/html', 'User-Agent': 'permission-load-test/1.0'})
        with OPENER.open(request, timeout=10) as response:
            response.read(256)
            status = response.status
    except Exception as exc:
        status = getattr(exc, 'code', None) or 'error'
    return {'status': status, 'ms': (time.perf_counter() - started) * 1000}

result = {'base': BASE, 'requests_per_endpoint': REQUESTS_PER_ENDPOINT, 'concurrency': CONCURRENCY, 'endpoints': {}}
with concurrent.futures.ThreadPoolExecutor(max_workers=CONCURRENCY) as pool:
    for path in ENDPOINTS:
        rows = list(pool.map(lambda _: hit(path), range(REQUESTS_PER_ENDPOINT)))
        latencies = [row['ms'] for row in rows]
        statuses = {}
        for row in rows:
            statuses[str(row['status'])] = statuses.get(str(row['status']), 0) + 1
        ordered = sorted(latencies)
        result['endpoints'][path] = {
            'total': len(rows),
            'errors': sum(1 for row in rows if row['status'] == 'error'),
            'statuses': statuses,
            'min_ms': round(min(latencies), 2),
            'avg_ms': round(statistics.mean(latencies), 2),
            'p95_ms': round(ordered[max(0, int(len(ordered) * 0.95) - 1)], 2),
            'max_ms': round(max(latencies), 2),
        }
print(json.dumps(result, ensure_ascii=False, indent=2))
