"""Can this machine reach Redis? Run it on the server, not locally.

    cd /var/www/html/strategist-ai && venv/bin/python scripts/check_redis.py

Separates the three things a failure could mean -- DNS, TCP/TLS, or Redis
itself -- because "TimeoutError" from inside the app says only that something
in that chain did not answer.
"""
import asyncio
import socket
import ssl
import sys
import time

sys.path.insert(0, ".")

from app.core.config import settings  # noqa: E402


def stage(label):
    print(f"  {label:<34}", end="", flush=True)


def ok(detail=""):
    print(f"OK  {detail}")


def fail(error):
    print(f"FAIL  {type(error).__name__}: {error}")


async def main():
    host, port = settings.REDIS_HOST, settings.REDIS_PORT
    print(f"\nRedis target: {host}:{port}  (TLS={settings.REDIS_SSL})\n")

    stage("1. DNS resolves")
    try:
        addresses = {a[4][0] for a in socket.getaddrinfo(host, port)}
        ok(", ".join(sorted(addresses)))
    except Exception as error:
        fail(error)
        print("\n-> DNS is the problem. Nothing else will work.")
        return

    stage("2. TCP connects")
    started = time.monotonic()
    try:
        conn = socket.create_connection((host, port), timeout=5)
        ok(f"{(time.monotonic() - started) * 1000:.0f}ms")
    except Exception as error:
        fail(error)
        print("\n-> The port is unreachable. Check the Azure Redis firewall "
              "allows this server's outbound IP, and that any egress rule "
              f"permits {port}.")
        return

    stage("3. TLS handshake")
    try:
        if settings.REDIS_SSL:
            context = ssl.create_default_context()
            with context.wrap_socket(conn, server_hostname=host) as tls:
                ok(tls.version())
        else:
            conn.close()
            ok("skipped, TLS off")
    except Exception as error:
        fail(error)
        print("\n-> TCP works but TLS does not. Check REDIS_SSL matches the "
              "port: 6380 is TLS, 6379 is not.")
        return

    stage("4. AUTH and PING")
    from app.services.infra.redis import get_control_client

    started = time.monotonic()
    try:
        client = get_control_client()
        async with client:
            await client.ping()
        ok(f"{(time.monotonic() - started) * 1000:.0f}ms")
    except Exception as error:
        fail(error)
        print("\n-> The socket opens but Redis will not complete the "
              "handshake. Most often the credentials, or the connection limit "
              "for the tier: check Connected Clients in the Azure portal.")
        return

    stage("5. Write, read, delete")
    try:
        client = get_control_client()
        async with client:
            await client.set("galaxiq:healthcheck", "1", ex=10)
            value = await client.get("galaxiq:healthcheck")
            await client.delete("galaxiq:healthcheck")
        ok(f"round-tripped {value!r}")
    except Exception as error:
        fail(error)
        return

    print("\nRedis is reachable and writable from this machine.")
    print("If /catalog/build still fails, the problem is not connectivity.\n")


if __name__ == "__main__":
    asyncio.run(main())
