#ifndef LOW_LEVEL_DISPLAY_ST7796_H
#define LOW_LEVEL_DISPLAY_ST7796_H

#include "low_level_display.h"
#include "st7796.h"
#include <climits>

class LowLevelDisplayST7796 : public LowLevelDisplay {
private:
    const st7796_config* config;
    int width;
    int height;
    bool initialized;
    uint16_t* rgb_buffer;  // Persistent buffer for 1-bit to RGB565 conversion
    bool invert_color;     // If true, swap black/white

    // Dirty rectangle tracking for partial updates
    uint8_t* prev_bit_buffer;  // Previous frame buffer for change detection
    bool dirty_rect_enabled;   // Enable/disable dirty rectangle optimization

    struct DirtyRect {
        int x0, y0;  // Top-left corner
        int x1, y1;  // Bottom-right corner (inclusive)
        bool is_valid;

        void reset() {
            x0 = INT_MAX;
            y0 = INT_MAX;
            x1 = -1;
            y1 = -1;
            is_valid = false;
        }

        void expand(int x, int y) {
            if (x < x0) x0 = x;
            if (x > x1) x1 = x;
            if (y < y0) y0 = y;
            if (y > y1) y1 = y;
            is_valid = true;
        }

        int get_width() const { return is_valid ? (x1 - x0 + 1) : 0; }
        int get_height() const { return is_valid ? (y1 - y0 + 1) : 0; }
        int get_area() const { return is_valid ? get_width() * get_height() : 0; }

        bool overlaps(const DirtyRect& other) const {
            if (!is_valid || !other.is_valid) return false;
            return !(x1 < other.x0 || x0 > other.x1 || y1 < other.y0 || y0 > other.y1);
        }

        void merge(const DirtyRect& other) {
            if (!other.is_valid) return;
            if (!is_valid) {
                *this = other;
                return;
            }
            x0 = (x0 < other.x0) ? x0 : other.x0;
            y0 = (y0 < other.y0) ? y0 : other.y0;
            x1 = (x1 > other.x1) ? x1 : other.x1;
            y1 = (y1 > other.y1) ? y1 : other.y1;
        }
    };

    static constexpr int MAX_DIRTY_RECTS = 4;
    DirtyRect dirty_rects[MAX_DIRTY_RECTS];  // Support up to 4 dirty rectangles (4 quadrants)

public:
    LowLevelDisplayST7796(const st7796_config* cfg, int w, int h, bool invert = false);
    ~LowLevelDisplayST7796() override;

    // Core display operations - converts 1-bit to RGB565 internally
    bool init() override;
    void clear(bool white = true) override;
    void draw_pixel(int x, int y, bool white) override;
    void draw_buffer(const uint8_t* bit_buffer) override;
    void refresh() override;

    // Display properties
    int get_width() const override { return width; }
    int get_height() const override { return height; }
    DisplayType get_type() const override { return DISPLAY_TYPE_ST7796; }
    bool is_color() const override { return true; }

    // Backlight control
    void set_backlight(bool on) override;
    
    // Brightness control (0-100)
    void set_brightness(uint8_t brightness) override;
    uint8_t get_brightness() const override;
    
    // Power management
    void sleep();  // Put display to sleep (low power, touch still active)
    void wake();   // Wake display from sleep

    // Orientation control
    void set_rotation(uint8_t rotation) override;

    // Color inversion control
    void set_invert_color(bool inv) { invert_color = inv; }
    bool get_invert_color() const { return invert_color; }

    // Power saving hooks
    void on_idle_2min() override;
    void on_idle_10min() override;
    void on_user_interaction() override;

    // Dirty rectangle optimization control
    void enable_dirty_rect(bool enabled = true);
    bool is_dirty_rect_enabled() const { return dirty_rect_enabled; }

private:
    uint8_t saved_brightness = 100;
    bool is_dimmed = false;
    bool is_sleeping = false;
};

#endif // LOW_LEVEL_DISPLAY_ST7796_H
