import asyncio
import websockets
import json
from threading import Thread
import time

# ==============================
# GLOBAL DEĞİŞKENLER
# ==============================

_websocket = None
_loop = None
_sunucu = None
_bagli = False
_reconnect = True
_ping_suresi = 10

_on_mesaj = None
_on_baglanti = None
_on_kopma = None
_on_hata = None


# ==============================
# BAĞLANTI FONKSİYONU
# ==============================

def baglan(sunucu_adresi, reconnect=True, ping_suresi=10):
    global _sunucu, _reconnect, _ping_suresi
    _sunucu = sunucu_adresi
    _reconnect = reconnect
    _ping_suresi = ping_suresi

    Thread(target=_baslat).start()


def gonder(veri):
    if not _bagli:
        print("Bağlantı yok!")
        return

    mesaj = json.dumps(veri)
    asyncio.run_coroutine_threadsafe(_websocket.send(mesaj), _loop)


def odaya_katil(oda_adi):
    gonder({
        "tip": "oda_katil",
        "oda": oda_adi
    })


def baglantiyi_kes():
    global _reconnect
    _reconnect = False
    asyncio.run_coroutine_threadsafe(_websocket.close(), _loop)


# ==============================
# EVENT FONKSİYONLARI
# ==============================

def mesaj_geldiginde(fonksiyon):
    global _on_mesaj
    _on_mesaj = fonksiyon


def baglaninca(fonksiyon):
    global _on_baglanti
    _on_baglanti = fonksiyon


def kopunca(fonksiyon):
    global _on_kopma
    _on_kopma = fonksiyon


def hata_olunca(fonksiyon):
    global _on_hata
    _on_hata = fonksiyon


# ==============================
# INTERNAL ASYNC SİSTEM
# ==============================

async def _ping_loop():
    while _bagli:
        await asyncio.sleep(_ping_suresi)
        try:
            await _websocket.send(json.dumps({"tip": "ping"}))
        except:
            break


async def _calistir():
    global _websocket, _bagli

    while _reconnect:
        try:
            async with websockets.connect(_sunucu) as ws:
                _websocket = ws
                _bagli = True

                if _on_baglanti:
                    _on_baglanti()

                asyncio.create_task(_ping_loop())

                async for mesaj in ws:
                    veri = json.loads(mesaj)

                    if _on_mesaj:
                        _on_mesaj(veri)

        except Exception as e:
            if _on_hata:
                _on_hata(e)

        finally:
            _bagli = False
            if _on_kopma:
                _on_kopma()

            if _reconnect:
                time.sleep(3)


def _baslat():
    global _loop
    _loop = asyncio.new_event_loop()
    asyncio.set_event_loop(_loop)
    _loop.run_until_complete(_calistir())