#include "addressable_light_display.h"
#include "esphome/core/log.h"

namespace esphome::addressable_light {

static const char *const TAG = "addressable_light.display";

int AddressableLightDisplay::get_width_internal() { return this->width_; }
int AddressableLightDisplay::get_height_internal() { return this->height_; }

void AddressableLightDisplay::setup() {
  this->addressable_light_buffer_.resize(this->width_ * this->height_, {0, 0, 0, 0});
}

void AddressableLightDisplay::update() {
  if (!this->enabled_)
    return;

  this->do_update_();
  this->display();
}

void AddressableLightDisplay::display() {
  bool dirty = false;
  uint8_t old_r, old_g, old_b, old_w;
  Color *c;

  for (uint32_t offset = 0; offset < this->addressable_light_buffer_.size(); offset++) {
    c = &(this->addressable_light_buffer_[offset]);

    light::ESPColorView pixel = (*this->light_)[offset];

    // Track the original values for the pixel view. If it has changed updating, then
    // we trigger a redraw. Avoiding redraws == avoiding flicker!
    old_r = pixel.get_red();
    old_g = pixel.get_green();
    old_b = pixel.get_blue();
    old_w = pixel.get_white();

    pixel.set_rgbw(c->r, c->g, c->b, c->w);

    // If the actual value of the pixel changed, then schedule a redraw.
    if (pixel.get_red() != old_r || pixel.get_green() != old_g || pixel.get_blue() != old_b ||
        pixel.get_white() != old_w) {
      dirty = true;
    }
  }

  if (dirty) {
    this->light_->schedule_show();
  }
}

void HOT AddressableLightDisplay::draw_absolute_pixel_internal(int x, int y, Color color) {
  if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
    return;

  if (this->pixel_mapper_f_.has_value()) {
    // Params are passed by reference, so they may be modified in call.
    int index = (*this->pixel_mapper_f_)(x, y);
    if (index < 0 || static_cast<size_t>(index) >= this->addressable_light_buffer_.size())
      return;
    this->addressable_light_buffer_[index] = color;
  } else {
    this->addressable_light_buffer_[y * this->get_width_internal() + x] = color;
  }
}
}  // namespace esphome::addressable_light
