#include "lora_net.h"

#ifdef FEATURE_ENABLE_LORA
LoRa_E220 e220ttl(GPIO_LORA_TX, GPIO_LORA_RX, GPIO_LORA_AUX, 3, 4); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX AUX M0 M1
void printParameters(struct Configuration configuration);
void printModuleInformation(struct ModuleInformation moduleInformation);
#elif defined(FEATURE_ENABLE_UARTLORA)
SoftwareSerial SerialLoRa(GPIO_LORA_RX, GPIO_LORA_TX); // RX, TX
void Parse_LoRa_UartCommand(char input[], int size);
#endif

bool InitLoRa(void (*MPinHelper)(int, int))
{
    bool returnval = false;

#ifdef FEATURE_ENABLE_LORA

    e220ttl.setMPins = MPinHelper;
    returnval = e220ttl.begin();

    if (returnval == true)
    {
        ResponseStructContainer c;
        c = e220ttl.getConfiguration();
        // It's important get configuration pointer before all other operation
        Configuration configuration = *(Configuration *)c.data;
        Serial.println(c.status.getResponseDescription());
        Serial.println(c.status.code);

        ResponseStructContainer cMi;
        cMi = e220ttl.getModuleInformation();
        // It's important get information pointer before all other operation
        // ModuleInformation mi = *(ModuleInformation *)cMi.data;

        Serial.println(cMi.status.getResponseDescription());
        Serial.println(cMi.status.code);

        //	----------------------- DEFAULT TRANSPARENT WITH RSSI -----------------------
        configuration.ADDL = 0x02;
        configuration.ADDH = 0x00;

        configuration.CHAN = 23;

        configuration.SPED.uartBaudRate = UART_BPS_9600;
        configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
        configuration.SPED.uartParity = MODE_00_8N1;

        configuration.OPTION.subPacketSetting = SPS_200_00;
        configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_ENABLED;
        configuration.OPTION.transmissionPower = POWER_22;

        configuration.TRANSMISSION_MODE.enableRSSI = RSSI_ENABLED;
        configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
        configuration.TRANSMISSION_MODE.enableLBT = LBT_ENABLED;
        configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011;

        // Set configuration changed and set to not hold the configuration
        ResponseStatus rs = e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
        Serial.println(rs.getResponseDescription());
        Serial.println(rs.code);
        c.close();

        printParameters(configuration);
    }
    else
    {
        MaintainDTC(DTC_NO_LORA_FOUND, DTC_WARN, true);
    }
#elif defined(FEATURE_ENABLE_UARTLORA)
    SerialLoRa.begin(9600);
    returnval = true;
#endif
    return returnval;
}

void LoRa_Process()
{
#ifdef FEATURE_ENABLE_LORA
    if (e220ttl.available() > 1)
    {
        ResponseContainer rc = e220ttl.receiveMessageRSSI();
        // If something goes wrong, print error
        if (rc.status.code != 1)
        {
            Serial.println(rc.status.getResponseDescription());
        }
        else
        {
            // Print the data received
            Serial.println(rc.status.getResponseDescription());
            Serial.println(rc.data);
            Serial.print("RSSI: ");
            Serial.println(rc.rssi, DEC);
        }
    }
#elif defined(FEATURE_ENABLE_UARTLORA)

    static char packageInput[32];
    static bool packageReceived = false;
    static unsigned int bufferPtr = 0;
    int receivedSize = 0;

    while (SerialLoRa.available() && !packageReceived)
    {
        char c = SerialLoRa.read();

        // CR ignorieren (falls CRLF)
        if (c == '\r')
        {
            continue;
        }

        if (c == '\n')
        {
            // Zeilenende: String sauber terminieren, Größe setzen
            packageInput[bufferPtr] = '\0';
            receivedSize = bufferPtr;
            bufferPtr = 0;
            packageReceived = true;
            Debug_pushMessage("Got LoRa UART: %s\n", packageInput);
            break;
        }

        // Optional: in Uppercase wandeln (macht Kommandos robust)
        if (c >= 'a' && c <= 'z')
            c = (char)(c - 'a' + 'A');

        // Erlaubte Zeichen (Ziffern, Großbuchstaben, Space, Komma, Punkt, Semikolon)
        bool allowed =
            (c >= '0' && c <= '9') ||
            (c >= 'A' && c <= 'Z') ||
            (c == ' ' || c == ',' || c == '.' || c == ';');

        if (allowed)
        {
            if (bufferPtr < sizeof(packageInput) - 1)
            {
                packageInput[bufferPtr++] = c;
                packageInput[bufferPtr] = '\0'; // immer NUL-terminiert halten
            }
            else
            {
                Debug_pushMessage("Buffer overflow. Resetting buffer.\n");
                bufferPtr = 0;
            }
        }
        else
        {
            Debug_pushMessage("Invalid character received: %c\n", c);
        }
    }

    if (packageReceived)
    {
        // Hinweis: receivedSize ist jetzt strlen(packageInput), ohne \n/\r
        Parse_LoRa_UartCommand(packageInput, receivedSize);
        packageReceived = false;
    }

#endif
}

void sendStatus_LoRa()
{
#ifdef FEATURE_ENABLE_LORA
    struct
    {
        MessageType_t type = "STATUS";
        MessageStatus_t status;
    } __attribute__((packed)) sendStatus;

    sendStatus.status.nodeid = 0x0002;
    sendStatus.status.millis = millis();
    sendStatus.status.faction_active = 1;
    sendStatus.status.faction_1_timer = 0xBBBBBBBB;
    sendStatus.status.faction_2_timer = 0xCCCCCCCC;
    sendStatus.status.faction_3_timer = 0xDDDDDDDD;

    ResponseStatus rs = e220ttl.sendFixedMessage(0xFF, 0xFF, 23, (byte *)&sendStatus, sizeof(sendStatus));
    Serial.println(rs.getResponseDescription());

#elif defined(FEATURE_ENABLE_UARTLORA)

    SerialLoRa.print(PersistenceData.faction_1_timer);
    SerialLoRa.write(";");
    SerialLoRa.print(PersistenceData.faction_2_timer);
    SerialLoRa.write(";");
    SerialLoRa.print(PersistenceData.faction_3_timer);
    SerialLoRa.write(";");
    SerialLoRa.print(PersistenceData.activeFaction);
    SerialLoRa.write(";");
    SerialLoRa.print(globals.battery_level);
    SerialLoRa.write('\n');

#endif
}

#ifdef FEATURE_ENABLE_LORA

void printParameters(struct Configuration configuration)
{
    Serial.println("----------------------------------------");

    Serial.print(F("HEAD : "));
    Serial.print(configuration.COMMAND, HEX);
    Serial.print(" ");
    Serial.print(configuration.STARTING_ADDRESS, HEX);
    Serial.print(" ");
    Serial.println(configuration.LENGHT, HEX);
    Serial.println(F(" "));
    Serial.print(F("AddH : "));
    Serial.println(configuration.ADDH, HEX);
    Serial.print(F("AddL : "));
    Serial.println(configuration.ADDL, HEX);
    Serial.println(F(" "));
    Serial.print(F("Chan : "));
    Serial.print(configuration.CHAN, DEC);
    Serial.print(" -> ");
    Serial.println(configuration.getChannelDescription());
    Serial.println(F(" "));
    Serial.print(F("SpeedParityBit     : "));
    Serial.print(configuration.SPED.uartParity, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.SPED.getUARTParityDescription());
    Serial.print(F("SpeedUARTDatte     : "));
    Serial.print(configuration.SPED.uartBaudRate, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.SPED.getUARTBaudRateDescription());
    Serial.print(F("SpeedAirDataRate   : "));
    Serial.print(configuration.SPED.airDataRate, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.SPED.getAirDataRateDescription());
    Serial.println(F(" "));
    Serial.print(F("OptionSubPacketSett: "));
    Serial.print(configuration.OPTION.subPacketSetting, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.OPTION.getSubPacketSetting());
    Serial.print(F("OptionTranPower    : "));
    Serial.print(configuration.OPTION.transmissionPower, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.OPTION.getTransmissionPowerDescription());
    Serial.print(F("OptionRSSIAmbientNo: "));
    Serial.print(configuration.OPTION.RSSIAmbientNoise, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.OPTION.getRSSIAmbientNoiseEnable());
    Serial.println(F(" "));
    Serial.print(F("TransModeWORPeriod : "));
    Serial.print(configuration.TRANSMISSION_MODE.WORPeriod, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.TRANSMISSION_MODE.getWORPeriodByParamsDescription());
    Serial.print(F("TransModeEnableLBT : "));
    Serial.print(configuration.TRANSMISSION_MODE.enableLBT, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.TRANSMISSION_MODE.getLBTEnableByteDescription());
    Serial.print(F("TransModeEnableRSSI: "));
    Serial.print(configuration.TRANSMISSION_MODE.enableRSSI, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.TRANSMISSION_MODE.getRSSIEnableByteDescription());
    Serial.print(F("TransModeFixedTrans: "));
    Serial.print(configuration.TRANSMISSION_MODE.fixedTransmission, BIN);
    Serial.print(" -> ");
    Serial.println(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());

    Serial.println("----------------------------------------");
}
#endif
#ifdef FEATURE_ENABLE_UARTLORA
#include <ctype.h>

static void rstrip(char *s)
{
    size_t n = strlen(s);
    while (n && (s[n - 1] == '\r' || s[n - 1] == '\n' || isspace((unsigned char)s[n - 1])))
    {
        s[--n] = '\0';
    }
}
static void lstrip(char *s)
{
    size_t i = 0, n = strlen(s);
    while (i < n && isspace((unsigned char)s[i]))
        i++;
    if (i)
        memmove(s, s + i, n - i + 1);
}

void Parse_LoRa_UartCommand(char input[], int size)
{
    Debug_pushMessage("Start parsing, size: %d\n", size);

    // Auf mehreren Delimitern splitten: ;, CR, LF, Tabs/Spaces
    const char *delims = ";\r\n\t ";
    char *ptr;

    // erstes Token (Kommando)
    ptr = strtok(input, delims);
    if (!ptr)
    {
        Debug_pushMessage("No command token\n");
        return;
    }

    char command[16];
    strncpy(command, ptr, sizeof(command) - 1);
    command[sizeof(command) - 1] = '\0';
    lstrip(command);
    rstrip(command);

    // zweites Token (optional: Wert)
    ptr = strtok(NULL, delims);
    char value[16] = {0};
    if (ptr)
    {
        strncpy(value, ptr, sizeof(value) - 1);
        value[sizeof(value) - 1] = '\0';
        lstrip(value);
        rstrip(value);
    }

    Debug_pushMessage("Parsed LoRa UART Command: %s  Value: %s\n", command, value);

    if (!strcmp(command, "ENABLE"))
    {
        globals.timer_disabled = false;
        Debug_pushMessage("Enabled by LoRa\n");
    }
    else if (!strcmp(command, "DISABLE"))
    {
        globals.timer_disabled = true;
        Debug_pushMessage("Disabled by LoRa\n");
    }
    else if (!strcmp(command, "RESET"))
    {
        PersistenceData.activeFaction = NONE;
        PersistenceData.faction_1_timer = 0;
        PersistenceData.faction_2_timer = 0;
        PersistenceData.faction_3_timer = 0;
        Debug_pushMessage("Reset by LoRa\n");
    }
    else if (!strcmp(command, "TMRSTP"))
    {
        PersistenceData.activeFaction = NONE;
    }
    else if (!strcmp(command, "TMR1"))
    {
        PersistenceData.faction_1_timer = atol(value);
    }
    else if (!strcmp(command, "TMR2"))
    {
        PersistenceData.faction_2_timer = atol(value);
    }
    else if (!strcmp(command, "TMR3"))
    {
        PersistenceData.faction_3_timer = atol(value);
    }
    else if (!strcmp(command, "EFAC1"))
    {
        PersistenceData.activeFaction = FACTION_1;
    }
    else if (!strcmp(command, "EFAC2"))
    {
        PersistenceData.activeFaction = FACTION_2;
    }
    else if (!strcmp(command, "EFAC3"))
    {
        PersistenceData.activeFaction = FACTION_3;
    }
    else
    {
        Debug_pushMessage("Unknown command: %s\n", command);
    }
}
#endif
