#ifndef TACTILEIPC3D_DATA_BACKEND_H
#define TACTILEIPC3D_DATA_BACKEND_H

#include <QObject>
#include <QVector>
#include <QTimer>
#include <QString>
#include <functional>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <qtmetamacros.h>
#include "xlsxdocument.h"
#include "xlsxformat.h"
#include "data_frame.h"

class DataBackend : public QObject {
    Q_OBJECT
    Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
    Q_PROPERTY(bool playbackRunning READ playbackRunning NOTIFY playbackRunningChanged)
    Q_PROPERTY(double metricPeak READ metricPeak NOTIFY metricsChanged)
    Q_PROPERTY(double metricRms READ metricRms NOTIFY metricsChanged)
    Q_PROPERTY(double metricAvg READ metricAvg NOTIFY metricsChanged)
    Q_PROPERTY(double metricDelta READ metricDelta NOTIFY metricsChanged)
    Q_PROPERTY(double metricSum READ metricSum NOTIFY metricsChanged)

public:
    using RenderCallback = std::function<void(const DataFrame&)>;

    explicit DataBackend(QObject* parent = nullptr);

    int frameCount() const { return m_frames.size(); }
    bool playbackRunning() const { return m_playbackRunning; }
    double metricPeak() const { return m_metricPeak; }
    double metricRms() const { return m_metricRms; }
    double metricAvg() const { return m_metricAvg; }
    double metricDelta() const { return m_metricDelta; }
    double metricSum() const { return m_metricSum; }

    void setLiveRenderCallback(RenderCallback cb) { m_liveCallback = std::move(cb); }
    void setPlaybackRenderCallback(RenderCallback cb) { m_playbackCallback = std::move(cb); }

    void ingestFrame(const DataFrame& frame);

    Q_INVOKABLE void clear();
    Q_INVOKABLE bool exportJson(const QString& path) const;
    Q_INVOKABLE bool exportCsv(const QString& path) const;
    Q_INVOKABLE bool exportXlsx(const QString& path) const;
    Q_INVOKABLE bool importJson(const QString& path);
    Q_INVOKABLE bool importCsv(const QString& path);
    Q_INVOKABLE bool importXlsx(const QString& path);
    Q_INVOKABLE void startPlayback(int intervalMs);
    Q_INVOKABLE void stopPlayback();
    Q_INVOKABLE void exportHandler(const QUrl& folder, const QString& filename, 
        const QString& format, const QString& method);
signals:
    void frameCountChanged();
    void playbackRunningChanged();
    void metricsChanged();

private:
    bool loadJson_(const QByteArray& data);
    bool loadCsv_(const QByteArray& data);
    QByteArray buildJson_() const;
    QByteArray buildCsv_() const;
    bool buildXlsx_(const QString& path) const;

    void seedDebugFrames_();

    void emitFrame_(const DataFrame& frame, const RenderCallback& cb);
    void updateMetrics_(const DataFrame& frame);

    QVector<DataFrame> m_frames;
    QTimer m_playbackTimer;
    int m_playbackIndex = 0;
    bool m_playbackRunning = false;

    double m_metricPeak = 0.0;
    double m_metricRms = 0.0;
    double m_metricAvg = 0.0;
    double m_metricDelta = 0.0;
    double m_metricSum = 0.0;

    RenderCallback m_liveCallback;
    RenderCallback m_playbackCallback;
};

#endif // TACTILEIPC3D_DATA_BACKEND_H
