#include "rx8130_rtc.h"
#include "rx8130_time.h"
#include <array>

namespace {
constexpr int I2C_TIMEOUT_MS=50;
constexpr uint8_t REG_SECONDS=0x10,REG_FLAG=0x1d,REG_CONTROL0=0x1e,REG_CONTROL1=0x1f;
constexpr uint8_t REG_DIGITAL_OFFSET=0x30,FLAG_VOLTAGE_LOW=0x80;
}

esp_err_t Rx8130Rtc::read(uint8_t reg,uint8_t* data,size_t size) {
    if(!device_ || !data || !size) return ESP_ERR_INVALID_STATE;
    return i2c_master_transmit_receive(device_,&reg,1,data,size,I2C_TIMEOUT_MS);
}
esp_err_t Rx8130Rtc::write(uint8_t reg,const uint8_t* data,size_t size) {
    if(!device_ || !data || !size || size>7) return ESP_ERR_INVALID_STATE;
    std::array<uint8_t,8> wire{};wire[0]=reg;
    for(size_t i=0;i<size;++i) wire[i+1]=data[i];
    return i2c_master_transmit(device_,wire.data(),size+1,I2C_TIMEOUT_MS);
}
esp_err_t Rx8130Rtc::begin(i2c_master_bus_handle_t bus,uint8_t address) {
    if(!bus) return ESP_ERR_INVALID_ARG;
    i2c_device_config_t config{};config.dev_addr_length=I2C_ADDR_BIT_LEN_7;
    config.device_address=address;config.scl_speed_hz=400000;
    auto result=i2c_master_bus_add_device(bus,&config,&device_);
    if(result!=ESP_OK) {device_=nullptr;return result;}
    // Same base enable/control sequence used by M5Unified's MIT-licensed RX8130 driver.
    uint8_t control1=0;result=read(REG_CONTROL1,&control1,1);
    if(result==ESP_OK) {control1|=0x30;result=write(REG_CONTROL1,&control1,1);}
    const uint8_t zero=0;
    if(result==ESP_OK) result=write(REG_DIGITAL_OFFSET,&zero,1);
    if(result==ESP_OK) result=write(REG_CONTROL0,&zero,1);
    return result;
}
esp_err_t Rx8130Rtc::read_utc_ms(uint64_t& epoch_ms) {
    uint8_t flag=0;auto result=read(REG_FLAG,&flag,1);
    if(result!=ESP_OK) return result;
    if(flag&FLAG_VOLTAGE_LOW) return ESP_ERR_INVALID_STATE;
    uint8_t registers[7]{};result=read(REG_SECONDS,registers,sizeof(registers));
    if(result!=ESP_OK) return result;
    wearable::RtcFields value;
    if(!wearable::decode_rx8130(registers,sizeof(registers),value) ||
       !wearable::rtc_fields_to_epoch_ms(value,epoch_ms)) return ESP_ERR_INVALID_RESPONSE;
    return ESP_OK;
}
esp_err_t Rx8130Rtc::write_utc_ms(uint64_t epoch_ms) {
    uint8_t registers[7]{};
    if(!wearable::encode_rx8130(epoch_ms,registers,sizeof(registers))) return ESP_ERR_INVALID_ARG;
    return write(REG_SECONDS,registers,sizeof(registers));
}
