/**
 * @file TriggerBar.cpp
 */

#include "TriggerBar.h"
#include "Hub.h"
#include "Theme.h"

#include <QHBoxLayout>
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QSlider>
#include <QLabel>
#include <QPushButton>
#include <QRadioButton>
#include <QButtonGroup>
#include <cmath>

namespace shq {

/* Window presets (100 us .. 10 s), mirrors the web UI. */
static const double kWinVals[]   = {1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0};
static const char*  kWinLabels[] = {"100 us", "1 ms", "10 ms", "100 ms", "1 s", "10 s"};
static const int    kNumWins     = 6;
static const char*  kEdgeWire[]  = {"rising", "falling", "both"};

TriggerBar::TriggerBar(Hub* hub, QWidget* parent)
    : QWidget(parent), hub_(hub) {
    auto* lay = new QHBoxLayout(this);
    lay->setContentsMargins(6, 2, 6, 2);
    lay->setSpacing(6);

    lay->addWidget(new QLabel("Trig:", this));

    sigCombo_ = new QComboBox(this);
    sigCombo_->setMinimumWidth(150);
    lay->addWidget(sigCombo_);

    edgeCombo_ = new QComboBox(this);
    edgeCombo_->addItems({"Rising", "Falling", "Both"});
    lay->addWidget(edgeCombo_);

    lay->addWidget(new QLabel("Thr", this));
    thrSpin_ = new QDoubleSpinBox(this);
    thrSpin_->setRange(-1e12, 1e12);
    thrSpin_->setDecimals(6);
    thrSpin_->setMaximumWidth(100);
    lay->addWidget(thrSpin_);

    lay->addWidget(new QLabel("Win", this));
    winCombo_ = new QComboBox(this);
    for (int i = 0; i < kNumWins; i++) { winCombo_->addItem(kWinLabels[i]); }
    winCombo_->setCurrentIndex(3);   /* 100 ms */
    lay->addWidget(winCombo_);

    lay->addWidget(new QLabel("Pre", this));
    preSlider_ = new QSlider(Qt::Horizontal, this);
    preSlider_->setRange(0, 100);
    preSlider_->setValue(20);
    preSlider_->setMaximumWidth(90);
    lay->addWidget(preSlider_);
    preLbl_ = new QLabel("20%", this);
    preLbl_->setMinimumWidth(34);
    lay->addWidget(preLbl_);

    normRadio_   = new QRadioButton("Norm", this);
    singleRadio_ = new QRadioButton("1x", this);
    normRadio_->setChecked(true);
    auto* grp = new QButtonGroup(this);
    grp->addButton(normRadio_);
    grp->addButton(singleRadio_);
    lay->addWidget(normRadio_);
    lay->addWidget(singleRadio_);

    badge_ = new QLabel("[IDLE]", this);
    badge_->setMinimumWidth(90);
    lay->addWidget(badge_);

    armBtn_    = new QPushButton("Arm", this);
    disarmBtn_ = new QPushButton("Disarm", this);
    stopBtn_   = new QPushButton("Stop", this);
    lay->addWidget(armBtn_);
    lay->addWidget(disarmBtn_);
    lay->addWidget(stopBtn_);

    trigTimeLbl_ = new QLabel("", this);
    trigTimeLbl_->setStyleSheet("color:#a6adc8;");
    lay->addWidget(trigTimeLbl_);
    lay->addStretch(1);

    /* ── Wiring ── */
    auto cfg = [this]() { if (!updating_) { pullFromUi(); sendConfig(); } };
    connect(sigCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, [cfg](int){ cfg(); });
    connect(edgeCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, [cfg](int){ cfg(); });
    connect(thrSpin_, &QDoubleSpinBox::editingFinished, this, cfg);
    connect(winCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, [cfg](int){ cfg(); });
    connect(preSlider_, &QSlider::valueChanged, this, [this](int v) {
        preLbl_->setText(QString("%1%").arg(v));
    });
    connect(preSlider_, &QSlider::sliderReleased, this, cfg);
    connect(normRadio_, &QRadioButton::toggled, this, [cfg](bool){ cfg(); });

    connect(armBtn_, &QPushButton::clicked, this, [this]() {
        pullFromUi(); sendConfig(); hub_->sendArm();
    });
    connect(disarmBtn_, &QPushButton::clicked, this, [this]() {
        hub_->sendDisarm();
    });
    connect(stopBtn_, &QPushButton::clicked, this, [this]() {
        auto& t = hub_->trigger();
        t.stopped = !t.stopped;
        hub_->sendTrigStop(t.stopped);
    });

    refreshSignals();
    onTriggerStateChanged();
}

void TriggerBar::pullFromUi() {
    auto& t = hub_->trigger();
    t.signalKey  = sigCombo_->currentData().toString().toStdString();
    t.edge       = edgeCombo_->currentIndex();
    t.threshold  = thrSpin_->value();
    t.windowSec  = kWinVals[winCombo_->currentIndex()];
    t.prePercent = preSlider_->value();
    t.single     = singleRadio_->isChecked();
}

void TriggerBar::sendConfig() {
    auto& t = hub_->trigger();
    if (t.signalKey.empty()) { return; }
    hub_->sendSetTrigger(t.signalKey, kEdgeWire[t.edge], t.threshold,
                         t.windowSec, t.prePercent,
                         t.single ? "single" : "normal");
}

void TriggerBar::refreshSignals() {
    updating_ = true;
    QString prev = sigCombo_->currentData().toString();
    sigCombo_->clear();
    for (const auto& src : hub_->sources()) {
        for (const auto& sig : src.signals) {
            QString key = QString::fromStdString(src.id + ":" + sig.meta.name);
            sigCombo_->addItem(key, key);
        }
    }
    int idx = sigCombo_->findData(prev);
    if (idx >= 0) { sigCombo_->setCurrentIndex(idx); }
    updating_ = false;
}

void TriggerBar::onTriggerStateChanged() {
    const auto& t = hub_->trigger();
    QString badge; QColor c;
    if      (t.status == "armed")      { badge = "[ARMED]";      c = col::yellow(); }
    else if (t.status == "collecting") { badge = "[COLLECTING]"; c = col::blue(); }
    else if (t.status == "triggered")  { badge = "[TRIGGERED]";  c = col::green(); }
    else                               { badge = "[IDLE]";       c = col::overlay0(); }
    badge_->setText(badge);
    badge_->setStyleSheet(QString("color:%1; font-weight:bold;").arg(c.name()));

    stopBtn_->setVisible(!t.single);
    stopBtn_->setText(t.stopped ? "Run" : "Stop");

    if (t.hasTrigTime && (t.status == "collecting" || t.status == "triggered")) {
        trigTimeLbl_->setText(QString("t=%1").arg(t.trigTime, 0, 'f', 6));
    } else {
        trigTimeLbl_->clear();
    }
}

} /* namespace shq */
