#pragma once

#include "lumacs/buffer.hpp"
#include <memory>
#include <utility>
#include <algorithm>

namespace lumacs {

/// @brief Represents the visible area of the buffer in a window.
struct Viewport {
    int width = 0;             ///< Width in characters.
    int height = 0;            ///< Height in lines.
    int scroll_offset = 0;     ///< Vertical scroll (top-most visible line index).
    int horizontal_offset = 0; ///< Horizontal scroll (left-most visible column index).
};

/// @brief Represents a window displaying a buffer.
/// 
/// A Window holds a reference to a Buffer, a cursor position, and viewport settings.
/// It manages scrolling and cursor movement within the bounds of the buffer.
/// Multiple windows can display the same buffer.
class Window {
public:
    /// @brief Create a window displaying the given buffer.
    Window(std::shared_ptr<Buffer> buffer);
    ~Window();

    /// @brief Change the buffer displayed in this window.
    void set_buffer(std::shared_ptr<Buffer> buffer);
    
    // Accessors
    std::shared_ptr<Buffer> buffer_ptr() const { return buffer_; }
    Buffer& buffer() { return *buffer_; }
    const Buffer& buffer() const { return *buffer_; }

    /// @brief Set the cursor position, clamping it to valid buffer bounds.
    void set_cursor(Position pos);
    
    /// @brief Get the current cursor position.
    Position cursor() const { return cursor_; }

    // Movement
    void move_up();
    void move_down();
    void move_left();
    void move_right();
    void move_to_line_start();
    void move_to_line_end();

    // Viewport
    
    /// @brief Update the viewport dimensions (called by UI on resize).
    void set_viewport_size(int width, int height);
    
    /// @brief Get the current viewport state.
    const Viewport& viewport() const { return viewport_; }
    
    /// @brief Adjust scroll offset to keep cursor visible (auto-scroll).
    void adjust_scroll();
    
    /// @brief Explicitly scroll the view by a number of lines.
    /// @param lines Number of lines to scroll (positive = down, negative = up).
    void scroll_lines(int lines);
    
    /// @brief Get the range of line indices currently visible in the viewport.
    /// @return Pair of {start_line, end_line} (end_line is exclusive).
    std::pair<size_t, size_t> visible_line_range() const;

private:
    void clamp_cursor();

    std::shared_ptr<Buffer> buffer_;
    Position cursor_;
    Viewport viewport_;
    
    static constexpr int SCROLL_MARGIN = 3; ///< Lines of context to keep visible when scrolling.
};

} // namespace lumacs