/*
 * pixelHeader.cpp
 * 
 * Implementation of SevenSegmentStrip class for 7-segment LED displays
 * using WS2812B addressable strips with FastLED on ESP32.
 */

#include "pixelHeader.h"

// =============================================================================
// CONSTRUCTOR & INITIALIZATION
// =============================================================================

SevenSegmentStrip::SevenSegmentStrip() 
  : _leds(nullptr),
    _totalLeds(0),
    _digitCount(0),
    _dotCount(0),
    _ledsPerDigit(18),
    _mapping(DEFAULT_SEGMENT_MAPPING),
    _colonBlinkEnabled(false),
    _colonBlinkPeriod(1000),
    _colonBlinkLastToggle(0),
    _colonBlinkState(false),
    _colonColor(Colors::DEFAULT_COLON)
{
}

void SevenSegmentStrip::begin(CRGB* leds, uint16_t totalLeds, uint8_t digitCount,
                               uint8_t dotCount, uint8_t ledsPerDigit) {
  _leds = leds;
  _totalLeds = totalLeds;
  _digitCount = digitCount;
  _dotCount = dotCount;
  _ledsPerDigit = ledsPerDigit;
  
  // Validate configuration
  uint16_t expectedLeds = (_digitCount * _ledsPerDigit) + _dotCount;
  if (expectedLeds != _totalLeds) {
    Serial.println("[WARNING] SevenSegmentStrip: Total LEDs mismatch!");
    Serial.printf("  Expected: %d digits * %d + %d dots = %d LEDs\n",
                  _digitCount, _ledsPerDigit, _dotCount, expectedLeds);
    Serial.printf("  Provided: %d LEDs\n", _totalLeds);
  }
  
  // Allocate storage
  _digits.resize(_digitCount);
  _dots.resize(_dotCount);
  
  // Build layout
  rebuildLayout();
  
  // Initialize display
  clear();
}

void SevenSegmentStrip::setMapping(const std::array<uint8_t, 7>& newMapping) {
  _mapping = newMapping;
  // Note: caller should call rebuildLayout() if already initialized
}

void SevenSegmentStrip::rebuildLayout() {
  if (!_leds || _digitCount == 0) return;
  
  // Calculate layout for each digit
  for (uint8_t i = 0; i < _digitCount; i++) {
    calculateDigitLayout(i);
  }
  
  // Calculate dot positions (after first 2 digits by default)
  for (uint8_t i = 0; i < _dotCount; i++) {
    _dots[i].ledIndex = calculateDotLedIndex(i);
  }
}

// =============================================================================
// DIGIT DISPLAY METHODS
// =============================================================================

bool SevenSegmentStrip::setDigit(uint8_t digitIndex, uint8_t number, CRGB color) {
  if (!isValidDigitIndex(digitIndex) || number > 9) {
    return false;
  }
  
  return setDigitRaw(digitIndex, DIGIT_PATTERNS[number], color);
}

bool SevenSegmentStrip::setDigitRaw(uint8_t digitIndex, uint8_t segmentMask, CRGB color) {
  if (!isValidDigitIndex(digitIndex) || !_leds) {
    return false;
  }
  
  const DigitInfo& digit = _digits[digitIndex];
  
  // Set each segment based on mask
  for (uint8_t seg = 0; seg < 7; seg++) {
    bool segmentOn = (segmentMask & (1 << seg)) != 0;
    CRGB segColor = segmentOn ? color : Colors::OFF;
    
    const SegmentInfo& segInfo = digit.segments[seg];
    for (uint8_t led = 0; led < segInfo.ledCount; led++) {
      uint16_t ledIndex = segInfo.startLedIndex + led;
      if (ledIndex < _totalLeds) {
        _leds[ledIndex] = segColor;
      }
    }
  }
  
  return true;
}

void SevenSegmentStrip::setTime(uint8_t hour, uint8_t minute, CRGB digitColor) {
  // Split into individual digits
  uint8_t hourTens, hourOnes, minTens, minOnes;
  splitDigits(hour, hourTens, hourOnes);
  splitDigits(minute, minTens, minOnes);
  
  // Set each digit (assuming 4-digit display)
  if (_digitCount >= 4) {
    setDigit(0, hourTens, digitColor);
    setDigit(1, hourOnes, digitColor);
    setDigit(2, minTens, digitColor);
    setDigit(3, minOnes, digitColor);
  }
}

// =============================================================================
// COLON/DOT CONTROL
// =============================================================================

void SevenSegmentStrip::setColon(bool on, CRGB color) {
  if (!_leds) return;
  
  _colonColor = color;
  CRGB dotColor = on ? color : Colors::OFF;
  
  for (uint8_t i = 0; i < _dotCount; i++) {
    if (isValidDotIndex(i)) {
      _leds[_dots[i].ledIndex] = dotColor;
    }
  }
}

void SevenSegmentStrip::setColonBlink(bool enable, uint32_t periodMs) {
  _colonBlinkEnabled = enable;
  _colonBlinkPeriod = periodMs;
  
  if (enable) {
    _colonBlinkLastToggle = millis();
    _colonBlinkState = true;
    setColon(true, _colonColor);
  } else {
    setColon(false, _colonColor);
  }
}

// =============================================================================
// UPDATE & DISPLAY
// =============================================================================

void SevenSegmentStrip::update(uint32_t nowMs) {
  // Handle colon blinking
  if (_colonBlinkEnabled) {
    uint32_t elapsed = nowMs - _colonBlinkLastToggle;
    
    if (elapsed >= (_colonBlinkPeriod / 2)) {
      _colonBlinkState = !_colonBlinkState;
      _colonBlinkLastToggle = nowMs;
      setColon(_colonBlinkState, _colonColor);
    }
  }
  
  // Future: Handle other animations here
  // - Digit fade in/out
  // - Color transitions
  // - Segment wipes
  // - Rainbow effects
}

void SevenSegmentStrip::show() {
  FastLED.show();
}

void SevenSegmentStrip::clear() {
  if (!_leds) return;
  
  for (uint16_t i = 0; i < _totalLeds; i++) {
    _leds[i] = CRGB::Black;
  }
}

// =============================================================================
// ADVANCED SEGMENT ACCESS
// =============================================================================

bool SevenSegmentStrip::getSegmentLedRange(uint8_t digitIndex, Segment segment,
                                            uint16_t& outStart, uint8_t& outCount) const {
  if (!isValidDigitIndex(digitIndex) || segment > SEG_G) {
    return false;
  }
  
  const SegmentInfo& segInfo = _digits[digitIndex].segments[segment];
  outStart = segInfo.startLedIndex;
  outCount = segInfo.ledCount;
  return true;
}

bool SevenSegmentStrip::setSegmentColor(uint8_t digitIndex, Segment segment, CRGB color) {
  if (!isValidDigitIndex(digitIndex) || segment > SEG_G || !_leds) {
    return false;
  }
  
  const SegmentInfo& segInfo = _digits[digitIndex].segments[segment];
  for (uint8_t led = 0; led < segInfo.ledCount; led++) {
    uint16_t ledIndex = segInfo.startLedIndex + led;
    if (ledIndex < _totalLeds) {
      _leds[ledIndex] = color;
    }
  }
  
  return true;
}

// =============================================================================
// PRIVATE HELPER METHODS
// =============================================================================

void SevenSegmentStrip::calculateDigitLayout(uint8_t digitIndex) {
  if (digitIndex >= _digitCount) return;
  
  DigitInfo& digit = _digits[digitIndex];
  
  // Calculate starting LED index for this digit
  // Default layout: digit0, digit1, dots, digit2, digit3
  uint16_t startIndex;
  if (digitIndex < 2) {
    // First two digits come before dots
    startIndex = digitIndex * _ledsPerDigit;
  } else {
    // Remaining digits come after dots
    startIndex = (digitIndex * _ledsPerDigit) + _dotCount;
  }
  
  digit.startLedIndex = startIndex;
  
  // Calculate LED ranges for each segment based on physical mapping
  uint16_t currentLedOffset = 0;
  
  for (uint8_t physPos = 0; physPos < 7; physPos++) {
    uint8_t logicalSeg = _mapping[physPos];  // Which segment is at this physical position
    
    uint8_t ledCount = SegmentLedCount::counts[logicalSeg];
    
    digit.segments[logicalSeg].startLedIndex = startIndex + currentLedOffset;
    digit.segments[logicalSeg].ledCount = ledCount;
    
    currentLedOffset += ledCount;
  }
}

uint16_t SevenSegmentStrip::calculateDotLedIndex(uint8_t dotIndex) const {
  // Default: dots are positioned after first 2 digits
  // digit0 (18) -> digit1 (18) -> dot0 -> dot1 -> digit2 (18) -> digit3 (18)
  return (2 * _ledsPerDigit) + dotIndex;
}

bool SevenSegmentStrip::isValidDigitIndex(uint8_t digitIndex) const {
  return digitIndex < _digitCount;
}

bool SevenSegmentStrip::isValidDotIndex(uint8_t dotIndex) const {
  return dotIndex < _dotCount;
}

