#include "../headers/scstwappbackend.h"

ScStwAppBackend::ScStwAppBackend(QObject *parent) : QObject(parent)
{
    this->scStwClient = new ScStwClient(this);
    this->appSettings = new ScStwAppSettings(this->scStwClient, this);
    this->localRace = new ScStwRace(this);
    this->remoteRace = new ScStwRemoteMonitorRace(this->scStwClient, this);
    this->mode = LOCAL;

    connect(this->appSettings, &ScStwAppSettings::settingChanged, this, &ScStwAppBackend::handleSettingChange);

    this->appSettings->setDefaultSetting(ScStwSettings::BaseStationSetting::ReadySoundEnableSetting, false);
    this->appSettings->setDefaultSetting(ScStwSettings::BaseStationSetting::ReadySoundDelaySetting, 0);
    this->appSettings->setDefaultSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundEnableSetting, false);
    this->appSettings->setDefaultSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundDelaySetting, 0);

    this->appSettings->setDefaultSetting(ScStwAppSettings::AppThemeSetting, "Light");

    this->appSettings->setDefaultSetting(ScStwAppSettings::BaseStationIpSetting, "192.168.4.1");

    this->scStwClient->setIP(this->appSettings->readSetting(ScStwAppSettings::BaseStationIpSetting).toString());

    connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwAppBackend::baseStationStateChanged);
    connect(this->scStwClient, &ScStwClient::stateChanged, this, &ScStwAppBackend::refreshMode);
    connect(this, &ScStwAppBackend::baseStationStateChanged, this, &ScStwAppBackend::baseStationPropertiesChanged);

    this->localRace->addTimer(new ScStwTimer(this));
    this->reloadRaceSettings();

    this->timerTextRefreshTimer = new QTimer(this);
    this->timerTextRefreshTimer->setInterval(1);
    this->timerTextRefreshTimer->setSingleShot(true);
    this->timerTextRefreshTimer->connect(this->timerTextRefreshTimer, &QTimer::timeout, this, &ScStwAppBackend::refreshTimerText);
    this->refreshTimerText();
}

// ------------------------
// --- helper functions ---
// ------------------------

void ScStwAppBackend::refreshMode() {
    RaceMode newMode;
    if(this->scStwClient->getState() == ScStwClient::CONNECTED){
        newMode = REMOTE;
    }
    else {
        newMode = LOCAL;
    }

    if(this->mode != newMode){

        if(newMode == LOCAL){
            // if the new mode is local -> connection to base station has been lost

            // reset local race
            this->getRace()->reset();
        }

        this->mode = newMode;
        emit this->modeChanged();
        emit this->raceChanged();
        emit this->getRace()->stateChanged(this->getRace()->getState());
    }

}

void ScStwAppBackend::refreshTimerText() {

    // --- refresh timer text ---
    if(this->getRace()->getState() == ScStwRace::RUNNING) {
        emit this->getRace()->timersChanged();
    }

    // --- refresh next start action delay progress ---
    if(this->getRace()->getState() == ScStwRace::WAITING || this->getRace()->getState() == ScStwRace::PREPAIRING) {
        emit this->getRace()->nextStartActionDetailsChanged();
    }

    this->timerTextRefreshTimer->start();
}

// - athlete management -

// TODO: move to client
QVariant ScStwAppBackend::getAthletes() {
    QVariantMap reply = this->scStwClient->sendCommand(4003);

    if(reply["status"] != 200){
        //handle Error!!
        qDebug() << "+ --- error getting athletes: " << reply["status"];
        return false;
    }

    QVariantMap tmpAthletes = reply["data"].toMap();

    //qDebug() << tmpAthletes;

    return tmpAthletes;
}

bool ScStwAppBackend::createAthlete(QString userName, QString fullName) {

    QVariant requestData = QVariantMap({{"fullName", fullName}, {"userName", userName}});

    QVariantMap reply = this->scStwClient->sendCommand(4001, requestData.toJsonValue());

    if(reply["status"] != 200){
        //handle Error!!
        qDebug() << "+ --- error creating athlete: " << reply["status"];
        return false;
    }

    return true;
}

bool ScStwAppBackend::deleteAthlete( QString userName ){

    QVariant requestData = QVariantMap({{"userName", userName}});

    QVariantMap reply = this->scStwClient->sendCommand(4002, requestData.toJsonValue());

    if(reply["status"] != 200){
        //handle Error!!
        qDebug() << "+ --- error deleting athlete: " << reply["status"];
        return false;
    }

    return true;

}

bool ScStwAppBackend::selectAthlete( QString userName, int timerId ){

    QVariant requestData = QVariantMap({{"userName", userName}, {"timerId", timerId}});

    QVariantMap reply = this->scStwClient->sendCommand(4000, requestData.toJsonValue());

    if(reply["status"] != 200){
        //handle Error!!
        qDebug() << "+ --- error selecting athlete: " << reply["status"];
        return false;
    }

    return true;

}

QVariant ScStwAppBackend::getResults( QString userName ){
    QVariantMap reply = this->scStwClient->sendCommand(4004, userName);

    if(reply["status"] != 200){
        //handle Error!!
        qDebug() << "+ --- error getting results: " << reply["status"];
        return false;
    }

    QVariantList tmpAthletes = reply["data"].toList();

    //qDebug() << tmpAthletes;

    return tmpAthletes;
}

// -------------------------
// --- functions for qml ---
// -------------------------

ScStwRace* ScStwAppBackend::getRace() {
    switch (this->mode) {
    case LOCAL:
        return this->localRace;
    case REMOTE:
        return this->remoteRace;
    }
    return nullptr;
}

ScStwAppSettings * ScStwAppBackend::getSettings() {
    return this->appSettings;
}

ScStwClient* ScStwAppBackend::getScStwClient() {
    return this->scStwClient;
}

int ScStwAppBackend::getMode() {
    return this->mode;
}

void ScStwAppBackend::reloadRaceSettings() {
    this->getRace()->writeStartActionSetting(
                ScStwRace::AtYourMarks,
                this->appSettings->readSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundEnableSetting).toBool(),
                this->appSettings->readSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundDelaySetting).toDouble()
                );

    this->getRace()->writeStartActionSetting(
                ScStwRace::Ready,
                this->appSettings->readSetting(ScStwSettings::BaseStationSetting::ReadySoundEnableSetting).toBool(),
                this->appSettings->readSetting(ScStwSettings::BaseStationSetting::ReadySoundDelaySetting).toDouble()
                );

    this->getRace()->setSoundVolume(1);

    this->getRace()->setAllowAutomaticTimerDisable(true);

}

void ScStwAppBackend::reloadBaseStationIpAdress() {
    this->scStwClient->setIP(this->appSettings->readSetting(ScStwAppSettings::BaseStationIpSetting).toString());
}

void ScStwAppBackend::handleSettingChange(int keyInt, int keyLevel, QVariant value) {
    Q_UNUSED(value)

    if(keyInt == -1) {
        emit this->settingsChanged();
        return;
    }

    switch (keyLevel) {
    case 0: {
        // BaseStationSetting!!
        ScStwSettings::BaseStationSetting key = static_cast<ScStwSettings::BaseStationSetting>(keyInt);
        switch (key) {
        case ScStwSettings::BaseStationSetting::InvalidSetting:
            return;
        default:
            if(this->mode == LOCAL)
                this->reloadRaceSettings();
            return;
        }
        break;
    }
    case 1: {
        // BaseStationInternalSetting!!
        ScStwAppSettings::AppInternalSetting key = static_cast<ScStwAppSettings::AppInternalSetting>(keyInt);
        switch (key) {
        case ScStwAppSettings::InvalidSetting:
            return;
        case ScStwAppSettings::BaseStationIpSetting:
            this->reloadBaseStationIpAdress();
            break;
        default:
            break;
        }
        break;
    }
    }
}
