import threading
import logging
import json
import asyncio
from ariadne import QueryType, SubscriptionType, make_executable_schema, gql, ScalarType
from ariadne.asgi import GraphQL
from ariadne.asgi.handlers import GraphQLTransportWSHandler  # ← add this
from asyncio import CancelledError

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route, Mount
from api_clients.ringcentral.ringcentral_client import initialize_ringcentral_webhook
from schema import type_defs  # Import only type_defs, not schema
from websocket_tools import handle_ringcentral_payload
import traceback as tb

logging.basicConfig(
    filename='/var/www/gql/websockets/ringcentral_webhooks.log',
    level=logging.DEBUG,  # Set to DEBUG for more verbosity
    format='%(asctime)s %(levelname)s %(message)s'
)

query = QueryType()
subscription = SubscriptionType()
json_scalar = ScalarType("JSON")

@query.field("hello")
def resolve_hello(*_):
    logging.debug("resolve_hello called")
    return "Hello, world!"

notification_queue = asyncio.Queue()

@subscription.source("testCounter")
async def test_counter_generator(obj, info):
    count = 0
    logging.debug("test_counter_generator started")
    while True:
        await asyncio.sleep(2)  # send a value every 2 seconds
        count += 1
        logging.debug(f"testCounter yielding: {count}")
        yield count

@subscription.field("testCounter")
def test_counter_resolver(count, info):
    logging.debug(f"test_counter_resolver called with count: {count}")
    return count

@subscription.source("ringcentralNotification")
async def ringcentral_notification_generator(obj, info):
    logging.info("ringcentral_notification_generator started")
    try:
        while True:
            data = await notification_queue.get()
            logging.info(
                "ringcentral_notification_generator yielding: %s",
                json.dumps(data)
            )
            logging.info(
                "Notification queue size after get: %d",
                notification_queue.qsize()
            )
            yield data
    except CancelledError:
        logging.info("ringcentral_notification_generator cancelled (client disconnected)")
        raise
    except Exception:
        logging.error(
            "ringcentral_notification_generator crashed:\n%s",
            tb.format_exc()
        )

@subscription.field("ringcentralNotification")
def ringcentral_notification_resolver(event, info):
    logging.debug(f"ringcentral_notification_resolver called with event: {event}")
    return event

@json_scalar.serializer
def serialize_json(value):
    logging.debug(f"serialize_json called with value: {value}")
    return value

schema = make_executable_schema(type_defs, [query, subscription, json_scalar])


graphql_app = GraphQL(
    schema,
    debug=True,
    websocket_handler=GraphQLTransportWSHandler(),  # ← use the transport handler
)


def start_ringcentral_init():
    try:
        logging.info("Starting RingCentral webhook initialization thread")
        threading.Thread(target=initialize_ringcentral_webhook, daemon=True).start()
        logging.info("[INFO] RingCentral initialized successfully.")
    except Exception as e:
        logging.error(f"[ERROR] Failed to initialize RingCentral webhook: {e}")

# Call this at startup
start_ringcentral_init()

async def ringcentral_webhook(request):
    logging.info("ringcentral_webhook called")
    logging.debug("Request headers: %s", dict(request.headers))
    validation_token = request.headers.get("Validation-Token")

    if validation_token:
        logging.info(f"Received RingCentral validation request with token: {validation_token}")
        response = JSONResponse({"status": "validation"})
        response.headers["Validation-Token"] = validation_token
        return response

    try:
        payload = await request.json()
        logging.info(f"Received RingCentral webhook payload: {json.dumps(payload)}")
        # Add to database here
        handle_ringcentral_payload(payload)
        await notification_queue.put(payload)
        logging.info(f"Notification added to queue. Queue size: {notification_queue.qsize()}")
    except Exception as e:
        logging.error(f"Failed to parse JSON from webhook: {str(e)}")
        logging.error(tb.format_exc())

        # Always return 200 for RingCentral
    return JSONResponse({"status": "ok"})

starlette_app = Starlette(
    routes=[
        Mount("/subscription/", graphql_app),
        Route("/webhook/ringcentral", ringcentral_webhook, methods=["POST"]),
    ]
)

