/*
  _   _ _____ _______        _____  ____  _  __
 | \ | | ____|_   _\ \      / / _ \|  _ \| |/ /
 |  \| |  _|   | |  \ \ /\ / / | | | |_) | ' / 
 | |\  | |___  | |   \ V  V /| |_| |  _ <| . \ 
 |_| \_|_____| |_|    \_/\_/  \___/|_| \_\_|\_\


Modern Network Status Display (4G + WiFi)
Get 4G status, signal quality, and WiFi status from SQLite database config_table

Pour compiler:
g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status.cc -o /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status -lrgbmatrix -lsqlite3

Pour lancer:
sudo /var/www/moduleair_pro_4g/matrix/screenNetwork/network_status

Pour arréter:
sudo systemctl stop moduleair-boot.service
*/

#include "led-matrix.h"
#include "graphics.h"
#include <unistd.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <atomic>
#include <sqlite3.h>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <ctime>
#include <algorithm>
#include <cmath>
#include <math.h>

using rgb_matrix::RGBMatrix;
using rgb_matrix::Canvas;

std::atomic<bool> running(true);

// Define color codes for console output
#define RESET   "\033[0m"
#define RED     "\033[31m"
#define GREEN   "\033[32m"
#define YELLOW  "\033[33m"
#define BLUE    "\033[34m"
#define MAGENTA "\033[35m"
#define CYAN    "\033[36m"
#define WHITE   "\033[37m"

// Path to the SQLite database
const std::string DB_PATH = "/var/www/moduleair_pro_4g/sqlite/sensors.db";

// Animation counter for connection indicators
int animation_frame = 0;

void signal_handler(int signum) {
    running = false;
}

void log(const std::string& type, const std::string& message) {
    std::string color;
    
    if (type == "BLUE") color = BLUE;
    else if (type == "GREEN") color = GREEN;
    else if (type == "YELLOW") color = YELLOW;
    else if (type == "RED") color = RED;
    else color = WHITE;
    
    std::cout << color << message << RESET << std::endl;
}

// Function to get WiFi status from database
bool get_wifi_status(sqlite3* db, std::string& wifi_status) {
    sqlite3_stmt* stmt;
    bool status_found = false;
    
    log("BLUE", "Querying WiFi status from database...");
    
    const char* query = "SELECT value FROM config_table WHERE key='WIFI_status'";
    if (sqlite3_prepare_v2(db, query, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            wifi_status = (char*)sqlite3_column_text(stmt, 0);
            status_found = true;
            std::cout << "  WiFi Status: " << wifi_status << std::endl;
        } else {
            std::cout << "  No WiFi status found in config_table" << std::endl;
            wifi_status = "unknown";
        }
        sqlite3_finalize(stmt);
    }
    
    return status_found;
}

// Function to get 4G status from database
bool get_4g_status(sqlite3* db, std::string& network_status, int& signal_quality) {
    sqlite3_stmt* stmt;
    bool status_found = false;
    bool signal_found = false;
    
    log("BLUE", "Querying 4G status from database...");
    
    // Get network status
    const char* status_query = "SELECT value FROM config_table WHERE key='SARA_network_status'";
    if (sqlite3_prepare_v2(db, status_query, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            network_status = (char*)sqlite3_column_text(stmt, 0);
            status_found = true;
            std::cout << "  Network Status: " << network_status << std::endl;
        } else {
            std::cout << "  No network status found in config_table" << std::endl;
            network_status = "unknown";
        }
        sqlite3_finalize(stmt);
    }
    
    // Get signal quality
    const char* signal_query = "SELECT value FROM config_table WHERE key='SARA_signal_quality'";
    if (sqlite3_prepare_v2(db, signal_query, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            signal_quality = sqlite3_column_int(stmt, 0);
            signal_found = true;
            std::cout << "  Signal Quality: " << signal_quality << " dBm" << std::endl;
        } else {
            std::cout << "  No signal quality found in config_table" << std::endl;
            signal_quality = -999;
        }
        sqlite3_finalize(stmt);
    }
    
    return status_found || signal_found;
}

// Function to draw signal strength bars
void draw_signal_bars(Canvas* canvas, int x, int y, int signal_rssi) {
    rgb_matrix::Color bar_color;
    rgb_matrix::Color bg_color(0, 0, 0);
    
    // Convert RSSI to signal strength (0-5 bars)
    // RSSI scale: 0-31 (where 31 is strongest)
    int bars = 0;
    if (signal_rssi >= 20) bars = 5;      // Excellent (20-31)
    else if (signal_rssi >= 15) bars = 4; // Good (15-19)
    else if (signal_rssi >= 10) bars = 3; // Fair (10-14)
    else if (signal_rssi >= 5) bars = 2;  // Poor (5-9)
    else if (signal_rssi >= 1) bars = 1;  // Very Poor (1-4)
    else bars = 0; // No signal (0)
    
    // Choose color based on signal strength
    if (bars >= 4) bar_color = rgb_matrix::Color(0, 255, 0);      // Green - Excellent/Good
    else if (bars >= 2) bar_color = rgb_matrix::Color(255, 255, 0); // Yellow - Fair/Poor
    else if (bars >= 1) bar_color = rgb_matrix::Color(255, 165, 0); // Orange - Very Poor
    else bar_color = rgb_matrix::Color(255, 0, 0);                  // Red - No signal
    
    // Draw 5 signal bars of increasing height
    for (int i = 0; i < 5; i++) {
        int bar_height = (i + 1) * 2; // Heights: 2, 4, 6, 8, 10
        int bar_x = x + i * 3;
        
        // Clear the bar area first
        for (int bx = 0; bx < 2; bx++) {
            for (int by = 0; by < 10; by++) {
                canvas->SetPixel(bar_x + bx, y - by, 0, 0, 0);
            }
        }
        
        // Draw the bar if it should be active
        if (i < bars) {
            for (int bx = 0; bx < 2; bx++) {
                for (int by = 0; by < bar_height; by++) {
                    canvas->SetPixel(bar_x + bx, y - by, bar_color.r, bar_color.g, bar_color.b);
                }
            }
        }
    }
}

// Function to draw connection status icon
void draw_connection_icon(Canvas* canvas, int x, int y, const std::string& status) {
    rgb_matrix::Color icon_color;
    
    // Clear the icon area (20x20 pixels)
    for (int ix = 0; ix < 20; ix++) {
        for (int iy = 0; iy < 20; iy++) {
            canvas->SetPixel(x + ix, y + iy, 0, 0, 0);
        }
    }
    
    if (status == "connected") {
        icon_color = rgb_matrix::Color(0, 255, 0); // Green
        // Draw a checkmark
        // Simplified checkmark pattern
        for (int i = 0; i < 6; i++) {
            canvas->SetPixel(x + 5 + i, y + 10 + i/2, icon_color.r, icon_color.g, icon_color.b);
            canvas->SetPixel(x + 11 + i, y + 13 - i, icon_color.r, icon_color.g, icon_color.b);
        }
    } else if (status == "connecting") {
        // Animated connecting indicator
        icon_color = rgb_matrix::Color(255, 255, 0); // Yellow
        int frame = animation_frame % 8;
        
        // Draw rotating dots
        for (int i = 0; i < 8; i++) {
            if (i <= frame) {
                int dot_x = x + 10 + (int)(8 * cos(i * M_PI / 4));
                int dot_y = y + 10 + (int)(8 * sin(i * M_PI / 4));
                canvas->SetPixel(dot_x, dot_y, icon_color.r, icon_color.g, icon_color.b);
                canvas->SetPixel(dot_x+1, dot_y, icon_color.r, icon_color.g, icon_color.b);
            }
        }
    } else if (status == "booting") {
        icon_color = rgb_matrix::Color(255, 255, 0); // Changed from orange to yellow
        // Draw a simple but visible rotating indicator for booting - EVEN FASTER rotation
        int frame = (animation_frame / 2) % 2; // Much faster rotation - update every 2 frames
        
        // Draw a rotating cross/plus pattern
        int center_x = x + 10;
        int center_y = y + 10;
        
        // Clear area first
        for (int cx = -8; cx <= 8; cx++) {
            for (int cy = -8; cy <= 8; cy++) {
                if (center_x + cx >= 0 && center_y + cy >= 0) {
                    canvas->SetPixel(center_x + cx, center_y + cy, 0, 0, 0);
                }
            }
        }
        
        // Draw rotating lines based on frame - faster animation
        if (frame == 0) {
            // Vertical line
            for (int i = -6; i <= 6; i++) {
                canvas->SetPixel(center_x, center_y + i, icon_color.r, icon_color.g, icon_color.b);
                canvas->SetPixel(center_x + 1, center_y + i, icon_color.r, icon_color.g, icon_color.b);
            }
        } else { // frame == 1
            // Horizontal line  
            for (int i = -6; i <= 6; i++) {
                canvas->SetPixel(center_x + i, center_y, icon_color.r, icon_color.g, icon_color.b);
                canvas->SetPixel(center_x + i, center_y + 1, icon_color.r, icon_color.g, icon_color.b);
            }
        }
    } else if (status == "disconnected" || status == "error") {
        icon_color = rgb_matrix::Color(255, 0, 0); // Red
        // Draw an X
        for (int i = 0; i < 12; i++) {
            canvas->SetPixel(x + 4 + i, y + 4 + i, icon_color.r, icon_color.g, icon_color.b);
            canvas->SetPixel(x + 4 + i, y + 16 - i, icon_color.r, icon_color.g, icon_color.b);
        }
    } else {
        icon_color = rgb_matrix::Color(128, 128, 128); // Gray for unknown
        // Draw a question mark
        // Simplified question mark
        for (int i = 0; i < 8; i++) {
            canvas->SetPixel(x + 6 + i, y + 4, icon_color.r, icon_color.g, icon_color.b);
            canvas->SetPixel(x + 14, y + 5 + i/2, icon_color.r, icon_color.g, icon_color.b);
        }
        canvas->SetPixel(x + 10, y + 15, icon_color.r, icon_color.g, icon_color.b);
        canvas->SetPixel(x + 11, y + 15, icon_color.r, icon_color.g, icon_color.b);
    }
}

// Function to draw the entire network status screen (4G + WiFi)
void draw_network_screen(Canvas* canvas, const std::string& network_status, int signal_quality, const std::string& wifi_status) {
    rgb_matrix::Color white(255, 255, 255);
    rgb_matrix::Color cyan(0, 255, 255);
    rgb_matrix::Color bg_color(0, 0, 0);
    
    rgb_matrix::Font title_font, value_font, small_font;
    
    // Load fonts - try multiple font paths
    bool fonts_loaded = false;
    
    // Try the fonts from your working sensor display
    if (title_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") &&
        value_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") &&
        small_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf")) {
        fonts_loaded = true;
        std::cout << "Loaded fonts successfully (6x9)" << std::endl;
    }
    // Fallback: try alternative font names
    else if (title_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf") &&
             value_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf") &&
             small_font.LoadFont("/var/www/moduleair_pro_4g/matrix/fonts/4x6.bdf")) {
        fonts_loaded = true;
        std::cout << "Loaded fonts successfully (mixed)" << std::endl;
    }
    
    if (!fonts_loaded) {
        std::cerr << "Error loading fonts! Check font paths:" << std::endl;
        std::cerr << "  Looking for: /var/www/moduleair_pro_4g/matrix/fonts/6x9.bdf" << std::endl;
        std::cerr << "  Looking for: /var/www/moduleair_pro_4g/matrix/fonts/9x18B.bdf" << std::endl;
        std::cerr << "  Looking for: /var/www/moduleair_pro_4g/matrix/fonts/4x6.bdf" << std::endl;
        
        // Use a simple text-based display instead
        rgb_matrix::Color white(255, 255, 255);
        rgb_matrix::Color green(0, 255, 0);
        rgb_matrix::Color red(255, 0, 0);
        rgb_matrix::Color bg_color(0, 0, 0);
        
        // Draw basic status without fonts
        canvas->Clear();
        
        // Draw simple 4G status indicators using pixels
        if (network_status == "connected") {
            // Draw green rectangle for 4G
            for (int x = 10; x < 30; x++) {
                for (int y = 10; y < 20; y++) {
                    canvas->SetPixel(x, y, 0, 255, 0);
                }
            }
        } else {
            // Draw red rectangle for 4G
            for (int x = 10; x < 30; x++) {
                for (int y = 10; y < 20; y++) {
                    canvas->SetPixel(x, y, 255, 0, 0);
                }
            }
        }
        
        // Draw simple WiFi status indicators using pixels
        if (wifi_status == "connected") {
            // Draw green rectangle for WiFi
            for (int x = 35; x < 55; x++) {
                for (int y = 10; y < 20; y++) {
                    canvas->SetPixel(x, y, 0, 255, 0);
                }
            }
        } else if (wifi_status == "hotspot") {
            // Draw orange rectangle for WiFi hotspot
            for (int x = 35; x < 55; x++) {
                for (int y = 10; y < 20; y++) {
                    canvas->SetPixel(x, y, 255, 165, 0);
                }
            }
        } else {
            // Draw red rectangle for WiFi disconnected/unknown
            for (int x = 35; x < 55; x++) {
                for (int y = 10; y < 20; y++) {
                    canvas->SetPixel(x, y, 255, 0, 0);
                }
            }
        }
        
        // Only draw signal bars if 4G connected
        if (network_status == "connected") {
            draw_signal_bars(canvas, 70, 30, signal_quality);
        }
        
        std::cout << "Using fallback display (no fonts)" << std::endl;
        return;
    }
    
    // Clear screen
    canvas->Clear();
    
    // Draw title
    rgb_matrix::DrawText(canvas, title_font, 2, title_font.baseline() + 2, cyan, &bg_color, "NETWORK STATUS", 0);
    
    // Draw WiFi connection status section (moved to first)
    int wifi_y = 20;
    rgb_matrix::DrawText(canvas, value_font, 2, wifi_y, white, &bg_color, "WiFi:", 0);
    
    // Draw WiFi status text
    rgb_matrix::Color wifi_color;
    std::string wifi_text = wifi_status;
    std::transform(wifi_text.begin(), wifi_text.end(), wifi_text.begin(), ::toupper);
    
    if (wifi_status == "connected") {
        wifi_color = rgb_matrix::Color(0, 255, 0);       // Green
    } else if (wifi_status == "hotspot") {
        wifi_color = rgb_matrix::Color(255, 165, 0);     // Orange
        wifi_text = "HOTSPOT";
    } else if (wifi_status == "disconnected") {
        wifi_color = rgb_matrix::Color(255, 0, 0);       // Red
    } else {
        wifi_color = rgb_matrix::Color(128, 128, 128);   // Gray
        wifi_text = "UNKNOWN";
    }
    
    rgb_matrix::DrawText(canvas, value_font, 35, wifi_y, wifi_color, &bg_color, wifi_text.c_str(), 0);
    
    // Draw 4G connection status section (moved to second)
    int status_y = 30;
    rgb_matrix::DrawText(canvas, value_font, 2, status_y, white, &bg_color, "4G:", 0);
    
    // Draw 4G status text
    rgb_matrix::Color status_color;
    std::string status_text = network_status;
    std::transform(status_text.begin(), status_text.end(), status_text.begin(), ::toupper);
    
    if (network_status == "connected") {
        status_color = rgb_matrix::Color(0, 255, 0);     // Green
    } else if (network_status == "connecting") {
        status_color = rgb_matrix::Color(255, 255, 0);   // Yellow
    } else if (network_status == "booting") {
        status_color = rgb_matrix::Color(255, 255, 0);   // Yellow
        status_text = "BOOTING";
    } else if (network_status == "disconnected" || network_status == "error") {
        status_color = rgb_matrix::Color(255, 0, 0);     // Red
    } else {
        status_color = rgb_matrix::Color(128, 128, 128); // Gray
        status_text = "UNKNOWN";
    }
    
    rgb_matrix::DrawText(canvas, value_font, 25, status_y, status_color, &bg_color, status_text.c_str(), 0);
    
    // Only show 4G signal section if 4G connected (NOT for booting, disconnected, or error)
    if (network_status == "connected") {
        // Draw 4G signal strength section (moved higher to prevent truncation)
        int signal_y = 42;
        rgb_matrix::DrawText(canvas, value_font, 2, signal_y, white, &bg_color, "4G Signal:", 0);
        
        // Draw signal bars
        draw_signal_bars(canvas, 65, signal_y - 2, signal_quality);
        
        // Draw signal value with safe spacing from bottom edge
        if (signal_quality != -999) {
            std::stringstream ss;
            ss << "RSSI: " << signal_quality;
            rgb_matrix::DrawText(canvas, small_font, 2, signal_y + 8, white, &bg_color, ss.str().c_str(), 0);
            
            // Draw signal quality text based on RSSI
            std::string quality_text;
            rgb_matrix::Color quality_color;
            
            if (signal_quality >= 20) {
                quality_text = "EXCELLENT";
                quality_color = rgb_matrix::Color(0, 255, 0);
            } else if (signal_quality >= 15) {
                quality_text = "GOOD";
                quality_color = rgb_matrix::Color(0, 255, 0);
            } else if (signal_quality >= 10) {
                quality_text = "FAIR";
                quality_color = rgb_matrix::Color(255, 255, 0);
            } else if (signal_quality >= 5) {
                quality_text = "POOR";
                quality_color = rgb_matrix::Color(255, 165, 0);
            } else if (signal_quality >= 1) {
                quality_text = "VERY POOR";
                quality_color = rgb_matrix::Color(255, 0, 0);
            } else {
                quality_text = "NO SIGNAL";
                quality_color = rgb_matrix::Color(255, 0, 0);
            }
            
            // Position quality text on the right side with safe spacing
            rgb_matrix::DrawText(canvas, small_font, 70, signal_y + 8, quality_color, &bg_color, quality_text.c_str(), 0);
        } else {
            rgb_matrix::DrawText(canvas, small_font, 2, signal_y + 8, rgb_matrix::Color(128, 128, 128), &bg_color, "NO DATA", 0);
        }
    } else {
        // Clear the 4G signal area completely for all non-connected states
        for (int clear_x = 0; clear_x < 128; clear_x++) {
            for (int clear_y = 37; clear_y < 64; clear_y++) {
                canvas->SetPixel(clear_x, clear_y, 0, 0, 0);
            }
        }
        
        // Show appropriate message based on 4G status (safe positioning)
        int msg_y = 42;
        int msg_y_second_line = 52;

        if (network_status == "booting") {
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 255, 0), &bg_color, "4G: Initializing...", 0);
        } else if (network_status == "disconnected") {
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 0, 0), &bg_color, "4G: Connection lost", 0);
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y_second_line, rgb_matrix::Color(255, 0, 0), &bg_color, "    Try reconnect", 0);

        } else if (network_status == "error") {
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 0, 0), &bg_color, "4G: Modem error", 0);
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y_second_line, rgb_matrix::Color(255, 0, 0), &bg_color, "    Try reconnect", 0);

        } else if (network_status == "connecting") {
            rgb_matrix::DrawText(canvas, value_font, 2, msg_y, rgb_matrix::Color(255, 255, 0), &bg_color, "4G: Connecting...", 0);
        }
    }
    
    // Draw timestamp
    auto now = std::chrono::system_clock::now();
    auto time_t = std::chrono::system_clock::to_time_t(now);
    auto tm = *std::localtime(&time_t);
    
    std::stringstream time_ss;
    time_ss << std::put_time(&tm, "%H:%M:%S");
    
    rgb_matrix::DrawText(canvas, small_font, 2, 60, rgb_matrix::Color(100, 100, 100), &bg_color, 
                        ("Updated: " + time_ss.str()).c_str(), 0);
    
    animation_frame++;
}

int main(int argc, char *argv[]) {
    log("BLUE", "Network Status Display started");

    // Handle signals for graceful exit
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    // Initialize database connection
    sqlite3* db;
    std::cout << "Opening SQLite database at " << DB_PATH << std::endl;
    int rc = sqlite3_open(DB_PATH.c_str(), &db);
    if (rc) {
        std::cerr << "Error opening SQLite database: " << sqlite3_errmsg(db) << std::endl;
        sqlite3_close(db);
        return 1;
    }

    // Initialize LED matrix
    log("BLUE", "Initializing LED matrix...");
    RGBMatrix::Options defaults;
    defaults.hardware_mapping = "moduleair_pinout";
    defaults.rows = 64;
    defaults.cols = 128;
    defaults.chain_length = 1;
    defaults.parallel = 1;
    defaults.row_address_type = 3;
    defaults.show_refresh_rate = false;
    defaults.brightness = 100;
    defaults.pwm_bits = 1;
    defaults.panel_type = "FM6126A";
    defaults.disable_hardware_pulsing = false;

    rgb_matrix::RuntimeOptions runtime_opt;
    runtime_opt.gpio_slowdown = 4;
    runtime_opt.daemon = 0;
    runtime_opt.drop_privileges = 0;

    Canvas *canvas = RGBMatrix::CreateFromOptions(defaults, runtime_opt);
    if (canvas == NULL) {
        std::cerr << "Error creating LED matrix canvas" << std::endl;
        sqlite3_close(db);
        return 1;
    }
    log("GREEN", "LED matrix initialized successfully");

    // Main loop
    log("BLUE", "Starting network status display loop");
    while (running) {
        std::string network_status;
        int signal_quality;
        std::string wifi_status;
        
        // Get 4G status from database
        bool data_success = get_4g_status(db, network_status, signal_quality);
        
        if (!data_success) {
            std::cerr << "Error retrieving 4G data from database" << std::endl;
            network_status = "error";
            signal_quality = -999;
        }
        
        // Get WiFi status from database
        bool wifi_success = get_wifi_status(db, wifi_status);
        
        if (!wifi_success) {
            std::cerr << "Error retrieving WiFi data from database" << std::endl;
            wifi_status = "unknown";
        }
        
        // Draw the screen
        draw_network_screen(canvas, network_status, signal_quality, wifi_status);
        
        // Sleep before next update
        std::cout << "Update complete, sleeping for 5 seconds..." << std::endl;
        for (int i = 0; i < 5 && running; i++) {
            sleep(1); // Sleep in 1-second increments for responsive exit
        }
    }

    // Clean up
    std::cout << "Program terminating, cleaning up..." << std::endl;
    canvas->Clear();
    delete canvas;
    sqlite3_close(db);
    std::cout << "Network Status Display terminated" << std::endl;
    return 0;
}