/*
 * pixelClock.ino
 * 
 * Example sketch demonstrating the SevenSegmentStrip helper library
 * for 7-segment LED clock displays using WS2812B strips and FastLED.
 * 
 * This minimal example shows:
 * - Initialization of FastLED and SevenSegmentStrip
 * - Setting time display (HH:MM format)
 * - Non-blocking colon blink
 * - Proper update loop structure
 * 
 * Hardware Setup:
 * - ESP32 board
 * - WS2812B LED strip with 74 LEDs total:
 *   - 4 digits × 18 LEDs = 72 LEDs
 *   - 2 colon dots × 1 LED = 2 LEDs
 * - Data line connected to GPIO pin (default: pin 5)
 * 
 * Future Extensions:
 * - Add RTC module for real timekeeping (DS3231, ESP32 internal RTC)
 * - Implement color transitions and animations
 * - Add brightness control (FastLED.setBrightness())
 * - Per-segment color gradients
 * - Smooth fade transitions between digits
 */

#include <FastLED.h>
#include "pixelHeader.h"
#include <WiFi.h>
#include <time.h>

// =============================================================================
// WIFI & NTP CONFIGURATION
// =============================================================================

// WiFi credentials - CHANGE THESE TO YOUR NETWORK
#define WIFI_SSID       "XXXX"           // Your WiFi SSID
#define WIFI_PASSWORD   "XXXX"           // Your WiFi password

// NTP Time Server Configuration
#define NTP_SERVER      "pool.ntp.org"  // Primary NTP server
#define NTP_SERVER_2    "time.nist.gov" // Backup NTP server

// Timezone Configuration (in seconds from GMT)
// Examples:
//   UTC-5 (EST):        -5 * 3600
//   UTC-8 (PST):        -8 * 3600
//   UTC+0 (GMT):         0 * 3600
//   UTC+5:30 (IST):      5 * 3600 +30 * 6 0
#define GMT_OFFSET_SEC  (5 * 3600 + 30 * 60)     // Timezone offset in seconds (EST = -5 hours)
#define DAYLIGHT_OFFSET_SEC  3600       // Daylight saving offset (1 hour = 3600 seconds)

// =============================================================================
// HARDWARE CONFIGURATION
// =============================================================================

#define DATA_PIN        4       // GPIO pin for LED data (change as needed)
#define NUM_LEDS        74      // Total LEDs: 4 digits (72) + 2 dots (2)
#define NUM_DIGITS      4       // Number of 7-segment digits
#define NUM_DOTS        2       // Number of colon dots
#define LEDS_PER_DIGIT  18      // LEDs per digit

#define LED_TYPE        WS2812B
#define COLOR_ORDER     GRB     // Adjust based on your LED strip (GRB or RGB)

// =============================================================================
// GLOBAL OBJECTS
// =============================================================================

CRGB leds[NUM_LEDS];                    // FastLED array
SevenSegmentStrip display;              // Our 7-segment display helper

// =============================================================================
// DISPLAY CONFIGURATION
// =============================================================================

// Display colors (easily customizable)
const CRGB DIGIT_COLOR = CRGB::Blue;    // Color for digits
const CRGB COLON_COLOR = CRGB::Yellow;     // Color for colon dots

// Brightness (0-255)
const uint8_t BRIGHTNESS = 100;          // Start low to protect eyes/power supply

// Colon blink settings
const bool COLON_BLINK_ENABLED = true;  // true = blinking colon, false = solid
const uint32_t COLON_BLINK_PERIOD = 1000; // Blink period in ms (1000 = 1 second)

// =============================================================================
// WIFI & NTP FUNCTIONS
// =============================================================================

// Connect to WiFi
bool connectToWiFi() {
  Serial.println("Connecting to WiFi...");
  Serial.printf("SSID: %s\n", WIFI_SSID);
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  Serial.println();
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi connected successfully!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());
    Serial.print("Signal Strength (RSSI): ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dBm");
    return true;
  } else {
    Serial.println("WiFi connection failed!");
    return false;
  }
}

// Synchronize time with NTP server
bool syncTimeWithNTP() {
  Serial.println("\nSynchronizing time with NTP server...");
  
  // Configure time with NTP
  configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER, NTP_SERVER_2);
  
  // Wait for time to be set
  Serial.print("Waiting for NTP sync");
  int attempts = 0;
  struct tm timeinfo;
  
  while (!getLocalTime(&timeinfo) && attempts < 10) {
    delay(1000);
    Serial.print(".");
    attempts++;
  }
  Serial.println();
  
  if (attempts < 10) {
    Serial.println("Time synchronized successfully!");
    Serial.print("Current time: ");
    Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    return true;
  } else {
    Serial.println("Failed to sync time with NTP!");
    return false;
  }
}

// Get current time from ESP32 RTC
bool getCurrentTime(uint8_t &hour, uint8_t &minute, uint8_t &second) {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    return false;
  }
  
  hour = timeinfo.tm_hour;
  minute = timeinfo.tm_min;
  second = timeinfo.tm_sec;
  return true;
}

// =============================================================================
// SETUP
// =============================================================================

void setup() {
  // Initialize serial for debugging
  Serial.begin(115200);
  delay(500);
  Serial.println("\n=== PixelClock 7-Segment Display with WiFi NTP ===");
  Serial.println("Initializing...\n");
  
  // Initialize FastLED
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  FastLED.show();
  
  Serial.println("FastLED initialized:");
  Serial.printf("  Data Pin: %d\n", DATA_PIN);
  Serial.printf("  Total LEDs: %d\n", NUM_LEDS);
  Serial.printf("  Brightness: %d\n", BRIGHTNESS);
  Serial.println();
  
  // Initialize SevenSegmentStrip helper
  display.begin(leds, NUM_LEDS, NUM_DIGITS, NUM_DOTS, LEDS_PER_DIGIT);
  
  Serial.println("Display initialized:");
  Serial.printf("  Digits: %d\n", display.getDigitCount());
  Serial.printf("  Dots: %d\n", display.getDotCount());
  Serial.printf("  LEDs per digit: %d\n", display.getLedsPerDigit());
  Serial.println();
  
  // =============================================================================
  // WIFI & NTP INITIALIZATION
  // =============================================================================
  
  // Show "connecting" pattern on display (all segments dim)
  for (uint8_t i = 0; i < NUM_DIGITS; i++) {
    display.setDigit(i, 8, CRGB(20, 20, 20));  // Dim white "88"
  }
  display.show();
  
  // Connect to WiFi
  bool wifiConnected = connectToWiFi();
  
  if (wifiConnected) {
    // Sync time with NTP
    bool timeSynced = syncTimeWithNTP();
    
    if (timeSynced) {
      // Get current time and display it
      uint8_t hour, minute, second;
      if (getCurrentTime(hour, minute, second)) {
        Serial.printf("\nDisplaying current time: %02d:%02d\n", hour, minute);
        display.setTime(hour, minute, DIGIT_COLOR);
      }
      
      // Configure colon blink
      if (COLON_BLINK_ENABLED) {
        Serial.printf("Enabling colon blink (period: %d ms)\n", COLON_BLINK_PERIOD);
        display.setColonBlink(true, COLON_BLINK_PERIOD);
        display.setColon(true, COLON_COLOR);
      } else {
        Serial.println("Setting colon to solid ON");
        display.setColon(true, COLON_COLOR);
      }
      
      display.show();
      Serial.println("\n✓ Setup complete! Clock is now running with NTP time.\n");
    } else {
      // NTP sync failed - show error pattern (all red)
      Serial.println("\n✗ NTP sync failed - showing error pattern");
      for (uint8_t i = 0; i < NUM_DIGITS; i++) {
        display.setDigit(i, 8, CRGB::Red);
      }
      display.show();
    }
  } else {
    // WiFi failed - show error pattern (all red blinking)
    Serial.println("\n✗ WiFi connection failed - showing error pattern");
    for (uint8_t i = 0; i < NUM_DIGITS; i++) {
      display.setDigit(i, 8, CRGB::Red);
    }
    display.show();
  }
  
  Serial.println("Entering main loop...\n");
}

// =============================================================================
// MAIN LOOP
// =============================================================================

void loop() {
  // Get current time
  uint32_t now = millis();
  
  // ==========================================================================
  // UPDATE TIME FROM ESP32 RTC
  // ==========================================================================
  static uint8_t lastMinute = 255;  // Track last displayed minute
  static uint8_t lastSecond = 255;  // Track seconds for debugging
  static uint8_t curretBrightness = 50;
  
  uint8_t currentHour, currentMinute, currentSecond;
  
  if (getCurrentTime(currentHour, currentMinute, currentSecond)) {
    // Update display only when minute changes (saves processing)
    if (currentMinute != lastMinute) {
      lastMinute = currentMinute;
      
      // Update the clock display with current time
      display.setTime(currentHour, currentMinute, DIGIT_COLOR);
      
      // Optional: Print time update to Serial Monitor
      Serial.printf("Time updated: %02d:%02d:%02d\n", 
                    currentHour, currentMinute, currentSecond);
    }
    
    // Debug: Print every second (optional - comment out if too verbose)
    if (currentSecond != lastSecond) {
      lastSecond = currentSecond;
      // Uncomment next line to see time every second
      // Serial.printf("Current: %02d:%02d:%02d\n", currentHour, currentMinute, currentSecond);
    }
  }
  
  // Update display animations (handles colon blink)
  display.update(now);
  
  // Refresh LEDs
  display.show();
  
  FastLED.setBrightness(curretBrightness);
  curretBrightness++;

  if(curretBrightness == 255){
    curretBrightness = 50;
  }
  // Small delay to prevent excessive updates
  delay(100);  // 100ms is fine since we only update on minute change
  
  // ==========================================================================
  // AUTOMATIC NTP RE-SYNC (every 12 hours)
  // ==========================================================================
  static uint32_t lastNtpSync = 0;
  const uint32_t NTP_SYNC_INTERVAL = 12UL * 60UL * 60UL * 1000UL;  // 12 hours in ms
  
  if (now - lastNtpSync >= NTP_SYNC_INTERVAL) {
    lastNtpSync = now;
    Serial.println("\n--- Performing periodic NTP re-sync ---");
    
    if (WiFi.status() == WL_CONNECTED) {
      syncTimeWithNTP();
    } else {
      Serial.println("WiFi not connected, attempting to reconnect...");
      if (connectToWiFi()) {
        syncTimeWithNTP();
      }
    }
  }
  
  // ==========================================================================
  // FUTURE INTEGRATION POINTS:
  // ==========================================================================
  
  // 1. Real-time clock integration:
  //    - Read time from RTC module (DS3231, DS1307, etc.)
  //    - Or use ESP32 internal RTC with NTP sync
  //    - Update display when minute changes:
  //      static uint8_t lastMinute = 0;
  //      if (currentMinute != lastMinute) {
  //        display.setTime(currentHour, currentMinute, DIGIT_COLOR);
  //        lastMinute = currentMinute;
  //      }
  
  // 2. Animations:
  //    - Fade transition when digit changes
  //    - Rainbow cycle across segments
  //    - "Loading" wipe effect
  //    - Color temperature shift (day/night)
  
  // 3. User controls:
  //    - Buttons to set time
  //    - Potentiometer for brightness
  //    - Web interface (ESP32 WiFi)
  
  // 4. Effects examples:
  //    - Pulse brightness on the hour
  //    - Flash all segments briefly
  //    - Gradient across digit segments
}

// =============================================================================
// HELPER FUNCTIONS (for future use)
// =============================================================================

/*
// Example: Demonstrate all digits 0-9 in sequence
void demonstrateDigits() {
  for (uint8_t num = 0; num <= 9; num++) {
    display.clear();
    for (uint8_t digit = 0; digit < NUM_DIGITS; digit++) {
      display.setDigit(digit, num, DIGIT_COLOR);
    }
    display.show();
    delay(500);
  }
}

// Example: Rainbow effect on a single digit
void rainbowDigit(uint8_t digitIndex, uint8_t number, uint8_t hue) {
  CRGB color = CHSV(hue, 255, 255);
  display.setDigit(digitIndex, number, color);
}

// Example: Per-segment color (for advanced effects)
void customSegmentColors(uint8_t digitIndex) {
  display.setSegmentColor(digitIndex, SEG_A, CRGB::Red);
  display.setSegmentColor(digitIndex, SEG_B, CRGB::Orange);
  display.setSegmentColor(digitIndex, SEG_C, CRGB::Yellow);
  display.setSegmentColor(digitIndex, SEG_D, CRGB::Green);
  display.setSegmentColor(digitIndex, SEG_E, CRGB::Blue);
  display.setSegmentColor(digitIndex, SEG_F, CRGB::Indigo);
  display.setSegmentColor(digitIndex, SEG_G, CRGB::Violet);
}

// Example: Simulate time passing (for testing without RTC)
void simulateTime() {
  static uint32_t lastUpdate = 0;
  static uint8_t hour = 12;
  static uint8_t minute = 0;
  
  uint32_t now = millis();
  if (now - lastUpdate >= 1000) {  // Update every second (simulated)
    lastUpdate = now;
    minute++;
    if (minute >= 60) {
      minute = 0;
      hour++;
      if (hour >= 24) {
        hour = 0;
      }
    }
    display.setTime(hour, minute, DIGIT_COLOR);
  }
}
*/
