#include "device_status.h"
#include "rx8130_time.h"
#include <array>
#include <cassert>
#include <cstdio>
#include <limits>

using namespace wearable;
int main() {
    RtcFields leap{2028,2,29,2,23,59,58};
    uint64_t epoch=0;assert(rtc_fields_to_epoch_ms(leap,epoch));
    RtcFields decoded;assert(epoch_ms_to_rtc_fields(epoch,decoded));
    assert(decoded.year==2028 && decoded.month==2 && decoded.day==29 && decoded.weekday==2);
    std::array<uint8_t,7> registers{};assert(encode_rx8130(epoch,registers.data(),registers.size()));
    assert(decode_rx8130(registers.data(),registers.size(),decoded));
    assert(decoded.hour==23 && decoded.minute==59 && decoded.second==58);

    auto corrupt=registers;corrupt[0]=0x7a;assert(!decode_rx8130(corrupt.data(),corrupt.size(),decoded));
    for(auto& value:corrupt) value=0;
    assert(!decode_rx8130(corrupt.data(),corrupt.size(),decoded));
    corrupt[0]=0;corrupt[1]=0;corrupt[2]=0;corrupt[3]=3;corrupt[4]=1;corrupt[5]=1;corrupt[6]=0x28;
    assert(!decode_rx8130(corrupt.data(),corrupt.size(),decoded));
    RtcFields invalid_date{2025,2,29,6,0,0,0};assert(!rtc_fields_to_epoch_ms(invalid_date,epoch));

    // Cold boot can seed from RTC; monotonic time advances while offline.
    WallClock clock;assert(clock.sync(1791072000000.0,100,480));
    assert(clock.utc_ms(5100)==1791072005000ULL);
    assert(clock.local_ms(5100)==1791072005000LL+480*60000LL);
    // Gateway offset remains metadata; Demo display always uses UTC+8.
    assert(clock.sync(1791075600000.0,6000,-300));
    assert(clock.local_ms(7000)==1791075601000LL+480*60000LL);
    assert(!clock.sync(1,8000,0));
    assert(!clock.sync(1791075600000.0,8000,900));
    assert(clock.timezone_offset_minutes==-300 && clock.utc_ms(8000)==1791075602000ULL);
    WallClock unavailable;assert(unavailable.local_ms(100)==0);
    const auto check_demo=[&](RtcFields utc,RtcFields expected) {
        uint64_t utc_epoch=0;assert(rtc_fields_to_epoch_ms(utc,utc_epoch));
        // Both NVS cold boot and Gateway reconnect can supply offset=0.
        for(int offset:{0,-300,480}) {
            assert(clock.sync(double(utc_epoch),100,offset));
            assert(clock.utc_ms(100)==utc_epoch);
            RtcFields local;assert(epoch_ms_to_rtc_fields(uint64_t(clock.local_ms(100)),local));
            assert(local.year==expected.year && local.month==expected.month && local.day==expected.day);
            assert(local.hour==expected.hour && local.minute==expected.minute);
            assert(clock.utc_ms(1100)==utc_epoch+1000);
            // Encoding the RTC still receives UTC, never the display shift.
            assert(encode_rx8130(clock.utc_ms(100),registers.data(),registers.size()));
            RtcFields rtc;assert(decode_rx8130(registers.data(),registers.size(),rtc));
            assert(rtc.hour==utc.hour && rtc.day==utc.day && rtc.month==utc.month);
        }
    };
    check_demo({2026,10,5,1,0,30,0},{2026,10,5,1,8,30,0});
    check_demo({2026,10,5,1,16,30,0},{2026,10,6,2,0,30,0});
    check_demo({2026,10,31,6,16,30,0},{2026,11,1,0,0,30,0});
    check_demo({2026,12,31,4,16,30,0},{2027,1,1,5,0,30,0});
    check_demo({2028,2,29,2,16,30,0},{2028,3,1,3,0,30,0});
    std::puts("RX8130 UTC / fixed Demo UTC+8 / day, month, year, leap rollover PASS");
}
