#pragma once

#include <QQuickItem>
#include <QColor>
#include <algorithm>
#include <memory>
#include <qcolor.h>
#include <qcontainerfwd.h>
#include <qcoreapplication.h>
#include <qquickitem.h>
#include <qquickwindow.h>
#include <qsgnode.h>
#include <qsize.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <unordered_map>
#include "ringbuffer.h"
#include "nice_ticks.h"

class SparklinePlotItem : public QQuickItem {
    Q_OBJECT

    Q_PROPERTY(int viewCount READ viewCount WRITE setViewCount NOTIFY viewCountChanged)
    Q_PROPERTY(qulonglong viewStart READ viewStart WRITE setViewStart NOTIFY viewStartChanged)
    Q_PROPERTY(bool follow READ follow WRITE setFollow NOTIFY followChanged)
    Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor NOTIFY lineColorChanged)
    Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor NOTIFY gridColorChanged)
    Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor NOTIFY textColorChanged)
    Q_PROPERTY(int yTickCount READ yTickCount WRITE setYTickCount NOTIFY yTickCountChanged)
    Q_PROPERTY(int leftPadding READ leftPadding WRITE setLeftPadding NOTIFY leftPaddingChanged)
    Q_PROPERTY(int rightPadding READ rightPadding WRITE setRightPadding NOTIFY rightPaddingChanged)
    Q_PROPERTY(int topPadding READ topPadding WRITE setTopPadding NOTIFY topPaddingChanged)
    Q_PROPERTY(int bottomPadding READ bottomPadding WRITE setBottomPadding NOTIFY bottomPaddingChanged)

public:
    explicit SparklinePlotItem(QQuickItem* parent=nullptr);

    Q_INVOKABLE void append(float y);
    Q_INVOKABLE void clear();

    int viewCount() const { return m_viewCount; }
    void setViewCount(int c);

    qulonglong viewStart() const { return m_viewStart; }
    void setViewStart(qulonglong s);

    bool follow() const { return m_follow; }
    void setFollow(bool f);

    QColor lineColor() const { return m_lineColor; }
    void setLineColor(const QColor& c);

    QColor gridColor() const { return m_gridColor; }
    void setGridColor(const QColor& c);

    QColor textColor() const { return m_textColor; }
    void setTextColor(const QColor& c);

    int yTickCount() const { return m_yTickCount; }
    void setYTickCount(int c);

    int leftPadding() const { return m_leftPad; }
    void setLeftPadding(int v);

    int rightPadding() const { return m_rightPad; }
    void setRightPadding(int v);

    int topPadding() const { return m_topPad; }
    void setTopPadding(int v);

    int bottomPadding() const { return m_topPad; }
    void setBottomPadding(int v);

signals:
    void viewCountChanged();
    void viewStartChanged();
    void followChanged();
    void lineColorChanged();
    void gridColorChanged();
    void textColorChanged();
    void yTickCountChanged();
    void leftPaddingChanged();
    void rightPaddingChanged();
    void topPaddingChanged();
    void bottomPaddingChanged();

protected:
    QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;

private:
    QSGTexture* getTextTexture(const QString& text, const QFont& font, QSize* outSize = nullptr);
private:
    std::unique_ptr<RingBuffer<double>> m_buf;

    int m_viewCount = 300;
    qulonglong m_viewStart = 0;
    bool m_follow = true;

    QColor m_lineColor = QColor("#39D535");
    QColor m_gridColor = QColor(255, 255, 255, 35);
    QColor m_textColor = QColor(255, 255, 255, 200);

    int m_yTickCount = 5;
    int m_leftPad = 40;
    int m_rightPad = 0;
    int m_topPad = 10;
    int m_bottomPad = 18;

    struct TexEntry {
        QSGTexture* tex = nullptr;
        QSize size;
    };
    std::unordered_map<QString, TexEntry> m_textCache;
};
