#include "config.hpp"
#include "lorahandler.hpp"
#include "logger.h"
#include <ArduinoJson.h>

extern logging::Logger logger;
extern Config config;

LoraHandler::LoraHandler() {
    // Initialize with SX1278 radio
}

void LoraHandler::setup()
{
#ifdef MOCK_LORA
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Running in MOCK MODE - simulating LoRa reception!");
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Mock data will be generated every 10 calls");
    return;
#endif

    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Initializing SX1278 with RadioLib!");
    
    // Create new SPI instance for LoRa
    spi = new SPIClass(VSPI);
    spi->begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
    
    // Create SX1278 instance
    radio = new SX1278(new SPIDriver(spi, LORA_CS));
    
    // Configure RXEN/TXEN pins
    pinMode(LORA_RXEN, OUTPUT);
    pinMode(LORA_TXEN, OUTPUT);
    digitalWrite(LORA_RXEN, LOW);
    digitalWrite(LORA_TXEN, LOW);
    
    // Initialize LoRa module
    int state = radio->begin();
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "LoRa init failed: %i", state);
        while (true) {
            delay(1000);
        }
    }
    
    // Configure LoRa parameters
    long freq = config.loraConfig.frequency;
    state = radio->setFrequency(freq);
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setFrequency failed: %i", state);
    }
    
    state = radio->setSpreadingFactor(config.loraConfig.spreadingFactor);
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setSpreadingFactor failed: %i", state);
    }
    
    state = radio->setBandwidth(config.loraConfig.signalBandwidth);
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setBandwidth failed: %i", state);
    }
    
    state = radio->setCodingRate(config.loraConfig.codingRate4);
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setCodingRate failed: %i", state);
    }
    
    state = radio->setOutputPower(config.loraConfig.power);
    if (state != RADIOLIB_ERR_NONE)
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setOutputPower failed: %i", state);
    }
    
    // Enable CRC
    radio->setCRC(true);
    
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "SX1278 initialized successfully!");
    String currentLoRainfo = "LoRa Freq: " + String(freq) + " / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
}

ReceivedLoRaPacket LoraHandler::receivePacket()
{
    ReceivedLoRaPacket receivedLoraPacket;
    
#ifdef MOCK_LORA
    // Mock mode - simulate LoRa reception every 10 calls
    mockCounter++;
    if (mockCounter >= 10)
    {
        mockCounter = 0;
        
        // Create mock sensor data from sender
        float temp = 22.5 + (random(0, 50) / 100.0);  // 22.5 - 23.0°C
        int battery = 75 + random(0, 20);  // 75-95%
        int boot = 5;
        int update = 1;
        
        // Build JSON payload like sender would send
        JsonDocument doc;
        doc["temp"] = temp;
        doc["battery"] = battery;
        doc["boot"] = boot;
        doc["update"] = update;
        
        serializeJson(doc, receivedLoraPacket.text);
        
        // Simulate signal parameters
        receivedLoraPacket.rssi = -85 + random(0, 30);  // -85 to -55 dBm
        receivedLoraPacket.snr = 5.0 + (random(0, 100) / 100.0);  // 5.0 to 6.0 dB
        receivedLoraPacket.freqError = random(-1000, 1000);
        
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa Rx [MOCK]", "---> %s (RSSI: %d, SNR: %.1f)", 
                   receivedLoraPacket.text.c_str(), receivedLoraPacket.rssi, receivedLoraPacket.snr);
    }
    return receivedLoraPacket;
#else
    // Real hardware mode
    // Enable RX mode
    digitalWrite(LORA_RXEN, HIGH);
    digitalWrite(LORA_TXEN, LOW);
    
    int state = radio->receive(0);  // 0 = non-blocking
    
    if (state == RADIOLIB_ERR_RX_ONGOING)
    {
        // No packet received yet
        return receivedLoraPacket;
    }
    else if (state == RADIOLIB_ERR_NONE)
    {
        // Packet received!
        receivedLoraPacket.text = radio->readData();
        receivedLoraPacket.rssi = radio->getRSSI();
        receivedLoraPacket.snr = radio->getSNR();
        receivedLoraPacket.freqError = radio->getFrequencyError();
        
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa Rx", "---> %s (RSSI: %d, SNR: %.1f)", 
                   receivedLoraPacket.text.c_str(), receivedLoraPacket.rssi, receivedLoraPacket.snr);
    }
    else
    {
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa Rx", "Receive error: %i", state);
    }
    
    return receivedLoraPacket;
#endif
}