#include "device_status.h"
#include "monitor_view.h"
#include <cassert>
#include <cstdio>
#include <limits>
using namespace wearable;
int main() {
    assert(battery_percent(3300)==0 && battery_percent(4200)==100);
    assert(battery_percent(3750)==50 && battery_percent(2000)==0 && battery_percent(5000)==100);
    assert(battery_filter(0,3920)==3920 && battery_filter(3920,4000)==3930);
    assert(battery_filter(3920,3921)==3920 && battery_filter(3920,3924)==3921);
    assert(!battery_voltage_valid(0) && !battery_voltage_valid(1999) && !battery_voltage_valid(5001));
    assert(battery_voltage_valid(2000) && battery_voltage_valid(5000));
    BatteryStatus b;b.sample(-8,0);assert(!b.valid && b.failures==1 && b.last_error==-8);
    b.sample(0,0);assert(!b.valid && b.last_error==BatteryStatus::InvalidVoltage && b.failures==2);
    b.sample(0,3750);assert(b.valid && b.percent==50 && b.filtered_millivolts==3750 && b.last_error==0);
    b.sample(-7,0);b.sample(-5,0);b.sample(0,65000);
    assert(b.valid && b.percent==50 && b.filtered_millivolts==3750 && b.failures==5);
    b.sample(0,3830);assert(b.filtered_millivolts==3760 && b.last_error==0 && b.failures==5);
    assert(compact_rate(842)=="842B/s" && compact_rate(10000)=="10KB/s");
    assert(compact_rate(1200000)=="1.2MB/s" && compact_rate(123400000,1)=="123M/s");
    assert(compact_rate(999999)=="1MB/s" && compact_rate(-1)=="0B/s");
    assert(compact_rate(std::numeric_limits<double>::infinity())=="0B/s");

    // ---- Full calibration: raw stays truthful, display can reach 100% -----
    // A plain 98% estimate is NEVER promoted without PMIC full evidence.
    bool latch=false;
    assert(battery_percent(4120)==91); // raw estimate near the 4.15..4.20 gap
    assert(battery_display_percent(4120,false,true,latch)==91 && !latch);
    // External power + charge complete + voltage in the full band => 100%.
    assert(battery_display_percent(4160,true,true,latch)==100 && latch);
    // Latch survives small noise dips (hysteresis) while still charging-complete.
    assert(battery_display_percent(4140,true,true,latch)==100 && latch);
    // Falls below the release floor: calibration disengages.
    assert(battery_display_percent(4080,true,true,latch)==86 && !latch);
    // Charger resumes pushing current (no longer complete): disengage.
    latch=false;assert(battery_display_percent(4160,false,true,latch)==95 && !latch);
    // Unplugged: disengage even at high voltage.
    latch=false;assert(battery_display_percent(4160,true,false,latch)==95 && !latch);
    // Voltage at the floor but not yet loud => not full.
    latch=false;assert(battery_display_percent(4149,true,true,latch)==94 && !latch);
    assert(battery_display_percent(BATTERY_FULL_VOLTAGE_MV,true,true,latch)==100 && latch);
    // No oscillation: latch, a 4100 dip still shows 100, then a 4080 drops once.
    assert(battery_display_percent(4100,true,true,latch)==100);
    assert(battery_display_percent(BATTERY_FULL_RELEASE_MV-1,true,true,latch)
           ==battery_percent(BATTERY_FULL_RELEASE_MV-1) && !latch);

    // ---- Charge state mapping --------------------------------------------
    assert(charge_state(false,false,false)==ChargeState::Discharging);
    assert(charge_state(false,true,false)==ChargeState::Discharging); // no ext power wins
    assert(charge_state(true,true,false)==ChargeState::Charging);
    assert(charge_state(true,false,true)==ChargeState::Full);
    assert(charge_state(true,false,false)==ChargeState::ExternalIdle);

    // ---- BatteryStatus integrates flags into calibrated display ----------
    BatteryStatus full;
    full.sample(0,3900);
    assert(full.display_percent==battery_percent(full.filtered_millivolts));
    assert(full.charge==ChargeState::Discharging);
    full.external_power=true;full.charging=true;full.recalibrate();
    assert(full.charge==ChargeState::Charging);
    // Drive the filtered voltage up and mark the charger complete.
    for(int i=0;i<40;++i) full.sample(0,4200);
    assert(full.filtered_millivolts>=BATTERY_FULL_VOLTAGE_MV);
    full.charge_complete=true;full.charging=false;full.recalibrate();
    assert(full.percent<100); // raw estimate stays honest
    assert(full.display_percent==100 && full.charge==ChargeState::Full);
    // Unplug restores ordinary reporting without a 98<->100 flip.
    full.external_power=false;full.charge_complete=false;full.recalibrate();
    assert(full.display_percent==full.percent && full.charge==ChargeState::Discharging);

    std::puts("Battery percent/filter/invalid/full-calibration/charge-state and compact NET rates PASS");
}