import sys
import datetime
import requests
import threading
import json
from PyQt6 import QtWidgets, uic, QtGui, QtCore
from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
from queue import Queue

from requests.adapters import HTTPAdapter, Retry
from usbcardreader import UsbCardReader

app = QtWidgets.QApplication(sys.argv)

with open('config.json', 'r') as f:
    config = json.load(f)

session = requests.Session()
session.post(config['host'] + '/api/login', {'email':config['login'], 'password': config['password']})


retries = Retry(total=10,
                backoff_factor=1,
                status_forcelist=[ 500, 502, 503, 504 ],)

session.mount('https://', HTTPAdapter(max_retries=retries))


last_card = 0
last_time = datetime.datetime.now()

racers = []

log = []


with open('log.json', 'r') as f:
    log = json.loads(f.read())


queue = Queue()


class Worker(QtCore.QThread):
    returned_state = Signal(str)
    def __init__(self):
        super().__init__()
        self.returned_state.connect(self.handle_returned_state)
        self.worker_thread = threading.Thread(target=self.worker)
        self.worker_thread.start()

    def worker(self):
        while True:
            item = queue.get()
            log.append({
                'url': item['url'],
                'json': item['json'],
            })
            with open('log.json', 'w') as f:
                f.write(json.dumps(log))
            response = session.post(item['url'], json=item['json'])
            if response.status_code == 200:
                if item.get('on_success'):
                    item['on_success']()
                if item.get('message'):
                    self.returned_state.emit(f'{item['message']}')
            else:
                if item.get('failed'):
                    self.returned_state.emit(f'{item['failed']}')

            print(item, response)
    def handle_returned_state(self, state):
        mb = QtWidgets.QMessageBox(text=f"{state}")
        mb.exec()


worker = Worker()


def register_racer():
    card_id = last_card
    index = window.racers.currentIndex()
    if not index.data():
        mb = QtWidgets.QMessageBox(text='Prosím vyberte závodníka!')
        mb.exec()
        return
    racer_id = int(index.data().split(' ')[-1])
    try:
        starting_number = max(filter(lambda r: r['starting_number'], racers), key=lambda racer: racer['starting_number'])['starting_number'] + 1
    except ValueError:
        starting_number = 1
    racer = list(filter(lambda x: x['racer_id'] == racer_id, racers))[0]

    def register_update_racer():
        racer['card_id'] = card_id
        racer['starting_number'] = starting_number
        racer['started'] = False
        updateRacers()

    queue.put({
        'url': config['host'] + '/api/card/register',
        'json': {'racer_id': racer_id, 'starting_number': starting_number, 'card_id': card_id, 'time': datetime.datetime.now().strftime('%d.%m.%Y %H:%M:%S.%f')},
        'message': f"Úspěšné zaregistrování závodníka {racer['first_name']} {racer['last_name']} se startovním číslem {starting_number}!",
        'failed': f"Neúspěšná registrace závodníka {racer['first_name']} {racer['last_name']}",
        'on_success': register_update_racer,
    })


model = QtGui.QStandardItemModel()

def updateRacers():
    model.clear()
    for racer in racers:
        if racer['starting_number'] or racer['card_id']:
            continue
        item = QtGui.QStandardItem(f"{racer['last_name']} {racer['first_name']} {racer['date_of_birth']} {racer['racer_id']}")
        model.appendRow(item)


updateRacers()


def reload_racers():
    global racers
    response = session.get(config['host'] + '/api/racers')

    racers = response.json()
    updateRacers()


reload_racers()


def findByCard(card_id):
    for racer in racers:
        if racer['card_id'] == card_id:
            return racer


def updateLastCard(card_id):
    global last_card, last_time
    if card_id == last_card and datetime.datetime.now() - last_time < datetime.timedelta(seconds=15):
        return
    time = last_time = datetime.datetime.now()
    last_card = card_id
    window.lastCard.setText(str(card_id))

    racer = findByCard(card_id)
    if racer:
        if racer['started']:
            def finish_update_racer():
                racer['card_id'] = None
            queue.put({
                'url': config['host'] + '/api/card/unregister',
                'json': {'racer_id': racer['racer_id'], 'starting_number': racer['starting_number'], 'card_id': card_id, 'time': time.strftime('%d.%m.%Y %H:%M:%S.%f')},
                'message': f"Úspěšné odhlášení závodníka {racer['starting_number']}!",
                'failed': f"Neúspěšné odhlášení karty závodníka {racer['starting_number']}",
                'on_success': finish_update_racer,
            })
        else:
            def start_update_racer():
                racer['started'] = True
            queue.put({
                'url': config['host'] + '/api/station/register',
                'json': {'card_id': card_id, 'time': time.strftime('%d.%m.%Y %H:%M:%S.%f'), 'station_id': 1},
                'message': f"Úspěšné odstartování závodníka {racer['starting_number']}!",
                'failed': f"Núspěšné odstartování závodníka {racer['starting_number']}, prosím registraci opakujte!",
                'on_success': start_update_racer,
            })


UsbCardReader(updateLastCard)




window = uic.loadUi("registrace.ui")
window.racers.setModel(model)
window.register_racer.clicked.connect(register_racer)
window.reload_racers.clicked.connect(reload_racers)
window.show()


app.exec()
