"""
Full API Regression Test
Tests all non-paginated and paginated APIs to confirm stability.
"""
import asyncio
import logging
import uuid
from datetime import timedelta, datetime

import httpx
from httpx import AsyncClient, ASGITransport

# Disable noisy logging
logging.disable(logging.CRITICAL)

# Import after logging disabled
from app.main import app
from app.services.auth_service import AuthService


def make_tokens():
    return {
        "admin": AuthService.create_access_token(user_id=1, role="admin", expires_delta=timedelta(days=365)),
        "driver": AuthService.create_access_token(user_id=2, role="driver", expires_delta=timedelta(days=365)),
        "passenger": AuthService.create_access_token(user_id=17, role="passenger", expires_delta=timedelta(days=365)),
    }


BASE = "/api/v1"

# 1×1 PNG — valid profile image for register/profile tests
TINY_PNG_B64 = (
    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
)


async def run_tests():
    transport = ASGITransport(app=app)
    tokens = make_tokens()
    HA = {"Authorization": f"Bearer {tokens['admin']}"}
    HD = {"Authorization": f"Bearer {tokens['driver']}"}
    HP = {"Authorization": f"Bearer {tokens['passenger']}"}

    results = []
    async with AsyncClient(transport=transport, base_url="http://test") as c:

        # === AUTH ===
        reg_phone = f"+1{uuid.uuid4().int % 9000000000 + 1000000000:010d}"
        r_send = await c.post(f"{BASE}/auth/send-otp", json={"phone": reg_phone})
        r_ver = await c.post(
            f"{BASE}/auth/verify-otp",
            json={"phone": reg_phone, "otp": "123456"},
        )
        reg_token = r_ver.json().get("access_token", "")
        r = await c.post(
            f"{BASE}/auth/register",
            json={
                "phone": reg_phone,
                "role": "passenger",
                "first_name": "Test",
                "profile_picture_base64": TINY_PNG_B64,
            },
            headers={"Authorization": f"Bearer {reg_token}"},
        )
        results.append((
            "Auth POST /register (after OTP)",
            r.status_code,
            r.status_code == 201 and r_send.status_code == 200 and r_ver.status_code == 200,
        ))

        r = await c.post(f"{BASE}/auth/login", json={"email": "admin@test.com"})
        results.append(("Auth POST /login", r.status_code, r.status_code in [200, 401]))  # 401 if admin not in DB

        r = await c.post(f"{BASE}/auth/send-otp", json={"phone": "+1234567890"})
        results.append(("Auth POST /send-otp", r.status_code, r.status_code in [200, 400]))

        r = await c.post(f"{BASE}/auth/refresh-token", json={"refresh_token": "dummy"})
        results.append(("Auth POST /refresh-token", r.status_code, r.status_code in [200, 401]))

        r = await c.post(f"{BASE}/auth/logout", headers=HP)
        results.append(("Auth POST /logout", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/auth/me", headers=HP)
        results.append(("Auth GET /me", r.status_code, r.status_code == 200))

        r = await c.put(
            f"{BASE}/auth/profile",
            json={"first_name": "Updated", "profile_picture_base64": TINY_PNG_B64},
            headers=HP,
        )
        results.append(("Auth PUT /profile", r.status_code, r.status_code == 200))

        # === ADMIN (non-paginated) ===
        r = await c.get(f"{BASE}/admin/dashboard", headers=HA)
        results.append(("Admin GET /dashboard", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/users/1", headers=HA)
        results.append(("Admin GET /users/1", r.status_code, r.status_code in [200, 404]))

        r = await c.put(f"{BASE}/admin/users/1/block", json={"is_blocked": False}, headers=HA)
        results.append(("Admin PUT /users/block", r.status_code, r.status_code == 200))

        r = await c.put(f"{BASE}/admin/drivers/1/verify", json={"status": "approved"}, headers=HA)
        results.append(("Admin PUT /drivers/verify", r.status_code, r.status_code in [200, 404]))

        r = await c.put(f"{BASE}/admin/withdrawals/1/process?approve=true", headers=HA)
        results.append(("Admin PUT /withdrawals/process", r.status_code, r.status_code in [200, 400, 404]))

        now = datetime.utcnow()
        later = datetime.utcnow() + timedelta(days=30)
        r = await c.post(f"{BASE}/admin/promo-codes", json={
            "code": f"TEST{uuid.uuid4().hex[:6].upper()}",
            "title": "Test Promo",
            "promo_type": "percentage",
            "discount_value": 10,
            "valid_from": now.strftime("%Y-%m-%dT%H:%M:%S"),
            "valid_until": later.strftime("%Y-%m-%dT%H:%M:%S"),
        }, headers=HA)
        results.append(("Admin POST /promo-codes", r.status_code, r.status_code in [200, 201]))

        # === DASHBOARD ===
        r = await c.get(f"{BASE}/admin/dashboard/stats", headers=HA)
        results.append(("Dashboard GET /stats", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/revenue?days=30", headers=HA)
        results.append(("Dashboard GET /revenue", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/map", headers=HA)
        results.append(("Dashboard GET /map", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/drivers?limit=5", headers=HA)
        results.append(("Dashboard GET /drivers", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/rides/stats", headers=HA)
        results.append(("Dashboard GET /rides/stats", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/reports/user-growth", headers=HA)
        results.append(("Dashboard GET /reports/user-growth", r.status_code, r.status_code == 200))

        # === RIDES ===
        r = await c.get(f"{BASE}/rides/categories")
        results.append(("Rides GET /categories", r.status_code, r.status_code == 200))

        r = await c.post(f"{BASE}/rides/estimate", json={
            "pickup": {"latitude": 28.6, "longitude": 77.2},
            "dropoff": {"latitude": 28.7, "longitude": 77.1},
            "vehicle_category_id": 1,
        }, headers=HP)
        results.append(("Rides POST /estimate", r.status_code, r.status_code == 200))

        r = await c.post(f"{BASE}/rides/book", json={
            "pickup": {"latitude": 28.6, "longitude": 77.2, "address": "A"},
            "dropoff": {"latitude": 28.7, "longitude": 77.1, "address": "B"},
            "vehicle_category_id": 1,
            "payment_method": "wallet",
        }, headers=HP)
        results.append(("Rides POST /book", r.status_code, r.status_code == 201))

        r = await c.get(f"{BASE}/rides/1", headers=HP)
        results.append(("Rides GET /1", r.status_code, r.status_code in [200, 404]))

        # === PASSENGER ===
        r = await c.get(f"{BASE}/passenger/profile", headers=HP)
        results.append(("Passenger GET /profile", r.status_code, r.status_code == 200))

        r = await c.put(
            f"{BASE}/passenger/profile",
            json={"first_name": "T", "profile_picture_base64": TINY_PNG_B64},
            headers=HP,
        )
        results.append(("Passenger PUT /profile", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/passenger/rides/active", headers=HP)
        results.append(("Passenger GET /rides/active", r.status_code, r.status_code == 200))

        # === PAYMENT ===
        r = await c.get(f"{BASE}/payments/wallet", headers=HP)
        results.append(("Payment GET /wallet", r.status_code, r.status_code == 200))

        r = await c.post(f"{BASE}/payments/wallet/topup", json={"amount": 100, "payment_method": "card"}, headers=HP)
        results.append(("Payment POST /wallet/topup", r.status_code, r.status_code == 200))

        # === DRIVER ===
        r = await c.get(f"{BASE}/driver/profile", headers=HD)
        results.append(("Driver GET /profile", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/driver/account-settings", headers=HD)
        results.append(("Driver GET /account-settings", r.status_code, r.status_code == 200))

        r = await c.put(f"{BASE}/driver/location", json={"latitude": 28.6, "longitude": 77.2}, headers=HD)
        results.append(("Driver PUT /location", r.status_code, r.status_code == 200))

        r = await c.put(f"{BASE}/driver/status", json={"is_online": True}, headers=HD)
        results.append(("Driver PUT /status", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/driver/earnings", headers=HD)
        results.append(("Driver GET /earnings", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/driver/rides/nearby", headers=HD)
        results.append(("Driver GET /rides/nearby", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/driver/rides/active", headers=HD)
        results.append(("Driver GET /rides/active", r.status_code, r.status_code == 200))

        # === OFFER PROFILES ===
        r = await c.get(f"{BASE}/driver/offer-profiles", headers=HD)
        results.append(("Offer GET list", r.status_code, r.status_code == 200))

        r = await c.put(f"{BASE}/driver/offer-profiles/priority", json={"profile_ids": [1]}, headers=HD)
        results.append(("Offer PUT /priority", r.status_code, r.status_code == 200))

        r = await c.post(f"{BASE}/driver/offer-profiles", json={
            "name": "Test", "enabled": True, "price_type": "price_per_km", "price_per_km": 50,
        }, headers=HD)
        results.append(("Offer POST", r.status_code, r.status_code == 201))

        # === CONFIG ===
        r = await c.get(f"{BASE}/config/settings", headers=HA)
        results.append(("Config GET /settings", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/config/map-providers", headers=HA)
        results.append(("Config GET /map-providers", r.status_code, r.status_code == 200))

        # === PAGINATED APIs ===
        r = await c.get(f"{BASE}/admin/users?page=1&limit=5", headers=HA)
        results.append(("Admin GET /users (paginated)", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/drivers/pending?page=1&limit=5", headers=HA)
        results.append(("Admin GET /drivers/pending", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/withdrawals/pending?page=1&limit=5", headers=HA)
        results.append(("Admin GET /withdrawals/pending", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/promo-codes?page=1&limit=5", headers=HA)
        results.append(("Admin GET /promo-codes", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/rides/live?page=1&limit=5", headers=HA)
        results.append(("Admin GET /rides/live", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/passenger/rides?page=1&limit=5", headers=HP)
        results.append(("Passenger GET /rides", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/payments/transactions?page=1&limit=5", headers=HP)
        results.append(("Payment GET /transactions", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/payments/withdrawals?page=1&limit=5", headers=HD)
        results.append(("Payment GET /withdrawals", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/rides/1/bids?page=1&limit=5", headers=HP)
        results.append(("Rides GET /1/bids", r.status_code, r.status_code in [200, 404]))

        r = await c.get(f"{BASE}/admin/dashboard/passengers?page=1&limit=5", headers=HA)
        results.append(("Dashboard GET /passengers", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/driver-verifications?page=1&limit=5", headers=HA)
        results.append(("Dashboard GET /driver-verifications", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/rides?page=1&limit=5", headers=HA)
        results.append(("Dashboard GET /rides", r.status_code, r.status_code == 200))

        r = await c.get(f"{BASE}/admin/dashboard/transactions?page=1&limit=5", headers=HA)
        results.append(("Dashboard GET /transactions", r.status_code, r.status_code == 200))

    return results


def main():
    print("=" * 60)
    print("FULL API REGRESSION TEST")
    print("=" * 60)
    results = asyncio.run(run_tests())
    passed = sum(1 for _, _, ok in results if ok)
    total = len(results)
    for name, code, ok in results:
        status = "PASS" if ok else "FAIL"
        print(f"  {status} ({code:3})  {name}")
    print("=" * 60)
    print(f"  {passed}/{total} passed")
    print("=" * 60)
    return 0 if passed == total else 1


if __name__ == "__main__":
    exit(main())
