/**
 * @file pmu_axp2101.cpp
 * @brief AXP2101 PMU 组件封装，基于 XPowersLib
 *
 * 保留原有 C 接口，内部迁移到 XPowersLib 组件 API。
 * 当前实现包含：
 * - 电源输出配置
 * - 充电配置
 * - 电池电量、电压、VBUS、温度读取
 * - Fuel Gauge 电池参数表加载
 * - 周期性 PMU 状态日志
 */

#include "pmu_axp2101.h"

#include <math.h>
#include <string.h>

#include "REG/AXP2101Constants.h"
#include "XPowersLib.h"
#include "XPowersParams.hpp"
#include "config.h"
#include "esp_check.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define TAG "PMU"
#define PMU_I2C_ADDR 0x34
#define PMU_I2C_TIMEOUT_MS 100
#define PMU_ALL_IRQ_MASK 0xFFFFFFUL

static i2c_master_dev_handle_t s_dev = NULL;
static bool s_ready = false;
static XPowersAXP2101 *s_pmu = nullptr;

static const uint8_t s_battery_param[128] = {
    0x01, 0xF5, 0x40, 0x00, 0x1B, 0x1E, 0x28, 0x0F, 0x0C, 0x1E, 0x32, 0x02, 0x14, 0x05, 0x0A, 0x04, 0x74, 0xFB, 0xFA,
    0x0D, 0x43, 0x00, 0x80, 0xFB, 0x55, 0x01, 0xEA, 0x05, 0x3D, 0xF6, 0x80, 0xF6, 0x76, 0xFB, 0x6C, 0x00, 0x5D, 0x00,
    0x58, 0xFB, 0x4E, 0x00, 0x3A, 0x00, 0x3A, 0xF6, 0x30, 0xF6, 0x26, 0xFB, 0x1C, 0x00, 0x0D, 0x00, 0x08, 0xFA, 0xFE,
    0xFF, 0xEA, 0xFF, 0xEA, 0xF5, 0xE0, 0xF5, 0xD6, 0xFA, 0xCC, 0xFF, 0xBD, 0xFF, 0xB8, 0xFA, 0xAE, 0x00, 0xF6, 0x00,
    0x00, 0xF6, 0x00, 0xF6, 0xC5, 0x98, 0x7E, 0x66, 0x4E, 0x44, 0x38, 0x1A, 0x12, 0x0A, 0xF6, 0x00, 0x00, 0xF6, 0x00,
    0xF6, 0x00, 0xFB, 0x00, 0x00, 0xFB, 0x00, 0x00, 0xFB, 0x00, 0x00, 0xF6, 0x00, 0x00, 0xF6, 0x00, 0xF6, 0x00, 0xFB,
    0x00, 0x00, 0xFB, 0x00, 0x00, 0xFB, 0x00, 0x00, 0xF6, 0x00, 0x00, 0xF6, 0x00, 0xF6,
};

static int pmu_component_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    if (s_dev == NULL || data == NULL || len == 0) {
        return -1;
    }

    esp_err_t ret = i2c_master_transmit_receive(s_dev, &reg_addr, 1, data, len, PMU_I2C_TIMEOUT_MS);
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "⚠️ PMU 寄存器读取失败 addr=0x%02X reg=0x%02X len=%u err=%s",
                 dev_addr, reg_addr, len, esp_err_to_name(ret));
        return -1;
    }

    return 0;
}

static int pmu_component_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    if (s_dev == NULL || data == NULL || len == 0) {
        return -1;
    }

    uint8_t buffer[17] = {0};
    if (len + 1 > sizeof(buffer)) {
        ESP_LOGE(TAG, "❌ PMU 寄存器写入长度过大 addr=0x%02X reg=0x%02X len=%u",
                 dev_addr, reg_addr, len);
        return -1;
    }

    buffer[0] = reg_addr;
    memcpy(&buffer[1], data, len);

    esp_err_t ret = i2c_master_transmit(s_dev, buffer, len + 1, PMU_I2C_TIMEOUT_MS);
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "⚠️ PMU 寄存器写入失败 addr=0x%02X reg=0x%02X len=%u err=%s",
                 dev_addr, reg_addr, len, esp_err_to_name(ret));
        return -1;
    }

    return 0;
}

static esp_err_t pmu_expect(bool ok, const char *step)
{
    if (!ok) {
        ESP_LOGE(TAG, "❌ PMU 组件调用失败: %s", step);
        return ESP_FAIL;
    }
    return ESP_OK;
}

static esp_err_t pmu_write_reg_checked(uint8_t reg, uint8_t value, const char *step)
{
    if (s_pmu == nullptr || s_pmu->writeRegister(reg, value) != 0) {
        ESP_LOGE(TAG, "❌ PMU 寄存器写入失败: %s reg=0x%02X value=0x%02X", step, reg, value);
        return ESP_FAIL;
    }
    return ESP_OK;
}

static float pmu_raw_ts_to_celsius(uint16_t raw)
{
    // AXP2101 TS ADC 分辨率为 0.5mV/LSB，当前板级热敏为 10K B3950。
    const float voltage_mv = raw * 0.5f;
    const float r_ntc = voltage_mv / 0.04f;

    if (r_ntc < 100.0f || r_ntc > 500000.0f) {
        return -999.0f;
    }

    const float ln_r = logf(r_ntc / 10000.0f);
    const float inv_t = (1.0f / 298.15f) + (1.0f / 3950.0f) * ln_r;
    return (1.0f / inv_t) - 273.15f;
}

static float pmu_validate_batt_temperature(float temp_c)
{
    // 先做保守保护，异常值不向上层透出。
    if (temp_c < 0.0f || temp_c > 60.0f) {
        return -999.0f;
    }
    return temp_c;
}

static esp_err_t pmu_write_battery_param(void)
{
    if (s_pmu == nullptr) {
        return ESP_ERR_INVALID_STATE;
    }

    ESP_LOGI(TAG, "⚡ 写入电池燃料计参数表");

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setRegisterBit(XPOWERS_AXP2101_RESET_FUEL_GAUGE, 2),
                                   "复位燃料计"),
                        TAG, "⚠️ 电量参数初始化失败");
    vTaskDelay(pdMS_TO_TICKS(10));

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->clrRegisterBit(XPOWERS_AXP2101_RESET_FUEL_GAUGE, 2),
                                   "释放燃料计复位"),
                        TAG, "⚠️ 电量参数初始化失败");
    vTaskDelay(pdMS_TO_TICKS(10));

    s_pmu->fuelGaugeControl(false, false);
    vTaskDelay(pdMS_TO_TICKS(10));
    s_pmu->fuelGaugeControl(false, true);
    vTaskDelay(pdMS_TO_TICKS(10));

    for (size_t i = 0; i < sizeof(s_battery_param); ++i) {
        ESP_RETURN_ON_ERROR(pmu_write_reg_checked(XPOWERS_AXP2101_BAT_PARAME,
                                                  s_battery_param[i],
                                                  "写入燃料计参数"),
                            TAG, "⚠️ 电量参数初始化失败");
    }

    s_pmu->fuelGaugeControl(false, false);
    vTaskDelay(pdMS_TO_TICKS(10));
    s_pmu->fuelGaugeControl(false, true);
    vTaskDelay(pdMS_TO_TICKS(10));

    for (size_t i = 0; i < sizeof(s_battery_param); ++i) {
        (void)s_pmu->getBatteryParameter();
    }

    s_pmu->fuelGaugeControl(false, false);
    vTaskDelay(pdMS_TO_TICKS(10));
    s_pmu->fuelGaugeControl(true, false);
    vTaskDelay(pdMS_TO_TICKS(10));

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setRegisterBit(XPOWERS_AXP2101_RESET_FUEL_GAUGE, 2),
                                   "重新触发燃料计复位"),
                        TAG, "⚠️ 电量参数初始化失败");
    vTaskDelay(pdMS_TO_TICKS(10));

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->clrRegisterBit(XPOWERS_AXP2101_RESET_FUEL_GAUGE, 2),
                                   "结束燃料计复位"),
                        TAG, "⚠️ 电量参数初始化失败");
    vTaskDelay(pdMS_TO_TICKS(10));

    ESP_LOGI(TAG, "✅ 电池燃料计参数加载完成");
    return ESP_OK;
}

static esp_err_t pmu_configure_charger(void)
{
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setVbusCurrentLimit(XPOWERS_AXP2101_VBUS_CUR_LIM_2000MA),
                                   "设置 VBUS 电流限制"),
                        TAG, "⚠️ 充电配置失败");
    s_pmu->setVbusVoltageLimit(XPOWERS_AXP2101_VBUS_VOL_LIM_4V36);
    s_pmu->setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_50MA);
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA),
                                   "设置恒流充电电流"),
                        TAG, "⚠️ 充电配置失败");
    s_pmu->setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_25MA);
    s_pmu->enableChargerTerminationLimit();
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2),
                                   "设置充电目标电压"),
                        TAG, "⚠️ 充电配置失败");
    s_pmu->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
    s_pmu->setLowBatWarnThreshold(10);
    s_pmu->setLowBatShutdownThreshold(5);
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setSysPowerDownVoltage(2600),
                                   "设置系统最低电压"),
                        TAG, "⚠️ 充电配置失败");

    ESP_LOGI(TAG, "⚡ 充电参数配置完成");
    return ESP_OK;
}

static esp_err_t pmu_configure_power_outputs(void)
{
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->setDC1Voltage(3400), "设置 DCDC1 电压"),
                        TAG, "⚠️ 电源输出配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableDC1(), "使能 DCDC1"),
                        TAG, "⚠️ 电源输出配置失败");

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->disableDC3(), "关闭 DCDC3"),
                        TAG, "⚠️ 电源输出配置失败");

    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->disableALDO2(), "关闭 ALDO2"),
                        TAG, "⚠️ 电源输出配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->disableALDO4(), "关闭 ALDO4"),
                        TAG, "⚠️ 电源输出配置失败");

    ESP_LOGI(TAG, "⚡ 电源输出配置完成：DCDC1 已开启，DCDC3/ALDO2/ALDO4 已关闭");
    return ESP_OK;
}

static esp_err_t pmu_configure_adc(void)
{
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableBattVoltageMeasure(), "启用电池电压 ADC"),
                        TAG, "⚠️ ADC 配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableVbusVoltageMeasure(), "启用 VBUS 电压 ADC"),
                        TAG, "⚠️ ADC 配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableSystemVoltageMeasure(), "启用系统电压 ADC"),
                        TAG, "⚠️ ADC 配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableTemperatureMeasure(), "启用芯片温度 ADC"),
                        TAG, "⚠️ ADC 配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableTSPinMeasure(), "启用 TS 引脚 ADC"),
                        TAG, "⚠️ ADC 配置失败");
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->enableBattDetection(), "启用电池检测"),
                        TAG, "⚠️ ADC 配置失败");

    int ts_ctrl = s_pmu->readRegister(XPOWERS_AXP2101_TS_PIN_CTRL);
    if (ts_ctrl < 0) {
        ESP_LOGE(TAG, "❌ 读取 TS 引脚配置失败");
        return ESP_FAIL;
    }

    ts_ctrl |= 0x01;
    ts_ctrl &= ~0x30;
    ts_ctrl |= 0x20;

    ESP_RETURN_ON_ERROR(pmu_write_reg_checked(XPOWERS_AXP2101_TS_PIN_CTRL,
                                              static_cast<uint8_t>(ts_ctrl),
                                              "配置 TS 电流源 40uA"),
                        TAG, "⚠️ ADC 配置失败");

    ESP_LOGI(TAG, "📊 ADC 测量配置完成");
    return ESP_OK;
}

static esp_err_t pmu_configure_irq(void)
{
    s_pmu->clearIrqStatus();
    ESP_RETURN_ON_ERROR(pmu_expect(s_pmu->disableIRQ(PMU_ALL_IRQ_MASK), "禁用 PMU 中断"),
                        TAG, "⚠️ 中断配置失败");
    ESP_LOGI(TAG, "⚙️ 中断配置完成");
    return ESP_OK;
}

static void pmu_dump_status(void)
{
    ESP_LOGI(TAG, "📊 ===== 电源状态摘要 =====");
    ESP_LOGI(TAG, "📊 DCDC1=%s %umV | DCDC3=%s %umV",
             s_pmu->isEnableDC1() ? "开" : "关", s_pmu->getDC1Voltage(),
             s_pmu->isEnableDC3() ? "开" : "关", s_pmu->getDC3Voltage());
    ESP_LOGI(TAG, "📊 ALDO2=%s %umV | ALDO4=%s %umV",
             s_pmu->isEnableALDO2() ? "开" : "关", s_pmu->getALDO2Voltage(),
             s_pmu->isEnableALDO4() ? "开" : "关", s_pmu->getALDO4Voltage());
    ESP_LOGI(TAG, "📊 低电量告警=%u%% | 关机阈值=%u%%",
             s_pmu->getLowBatWarnThreshold(), s_pmu->getLowBatShutdownThreshold());
    ESP_LOGI(TAG, "📊 ========================");
}

static void pmu_monitor_task(void *arg)
{
    (void)arg;
    ESP_LOGI(TAG, "⏰ PMU 监控任务启动，每 10 秒刷新一次");

    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10000));

        const int percent = pmu_get_battery_percent();
        const uint16_t vbat = pmu_get_batt_voltage();
        const uint16_t vbus = pmu_get_vbus_voltage();
        const bool charging = pmu_is_charging();
        const float batt_temp = pmu_get_batt_temperature();
        const float die_temp = pmu_get_die_temperature();

        ESP_LOGI(TAG, "📊 电量: %d%% | 电池: %umV | VBUS: %umV | %s",
                 percent, vbat, vbus, charging ? "🔌 充电中" : "⚡ 放电中");
        ESP_LOGI(TAG, "📊 电池温度: %.1f°C | 芯片温度: %.1f°C", batt_temp, die_temp);
    }
}

extern "C" esp_err_t axp2101_init(i2c_master_bus_handle_t i2c_bus)
{
    i2c_device_config_t dev_cfg = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,
        .device_address = PMU_I2C_ADDR,
        .scl_speed_hz = PMU_I2C_FREQ_HZ,
        .scl_wait_us = 0,
        .flags = {
            .disable_ack_check = false,
        },
    };

    esp_err_t ret = i2c_master_bus_add_device(i2c_bus, &dev_cfg, &s_dev);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "❌ I2C 设备添加失败: %s", esp_err_to_name(ret));
        return ret;
    }

    vTaskDelay(pdMS_TO_TICKS(50));

    if (s_pmu == nullptr) {
        s_pmu = new XPowersAXP2101(PMU_I2C_ADDR, pmu_component_read, pmu_component_write);
    }
    if (s_pmu == nullptr || !s_pmu->init()) {
        ESP_LOGE(TAG, "❌ XPowersLib 初始化失败，AXP2101 未响应");
        return ESP_FAIL;
    }

    ESP_LOGI(TAG, "🔧 AXP2101 芯片 ID: 0x%02X", s_pmu->getChipID());

    ESP_RETURN_ON_ERROR(pmu_write_battery_param(), TAG, "⚠️ PMU 电量校准失败");
    ESP_RETURN_ON_ERROR(pmu_configure_charger(), TAG, "⚠️ PMU 初始化失败");
    ESP_RETURN_ON_ERROR(pmu_configure_power_outputs(), TAG, "⚠️ PMU 初始化失败");
    ESP_RETURN_ON_ERROR(pmu_configure_adc(), TAG, "⚠️ PMU 初始化失败");
    ESP_RETURN_ON_ERROR(pmu_configure_irq(), TAG, "⚠️ PMU 初始化失败");

    s_ready = true;
    ESP_LOGI(TAG, "✅ AXP2101 初始化完成");
    pmu_dump_status();

    BaseType_t task_ok = xTaskCreate(pmu_monitor_task, "pmu_mon", 3072, NULL, 5, NULL);
    if (task_ok != pdPASS) {
        ESP_LOGE(TAG, "❌ PMU 监控任务创建失败");
        return ESP_FAIL;
    }

    return ESP_OK;
}

extern "C" int pmu_get_battery_percent(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return -1;
    }
    const int percent = s_pmu->getBatteryPercent();
    if (percent < 0 || percent > 100) {
        return -1;
    }
    return percent;
}

extern "C" bool pmu_is_charging(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return false;
    }
    return s_pmu->isCharging();
}

extern "C" uint16_t pmu_get_batt_voltage(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }
    return s_pmu->getBattVoltage();
}

extern "C" uint16_t pmu_get_vbus_voltage(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }
    return s_pmu->getVbusVoltage();
}

extern "C" uint16_t pmu_get_system_voltage(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }
    return s_pmu->getSystemVoltage();
}

extern "C" uint16_t pmu_get_charger_current_limit_ma(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }

    switch (s_pmu->getChargerConstantCurr()) {
    case XPOWERS_AXP2101_CHG_CUR_100MA:
        return 100;
    case XPOWERS_AXP2101_CHG_CUR_125MA:
        return 125;
    case XPOWERS_AXP2101_CHG_CUR_150MA:
        return 150;
    case XPOWERS_AXP2101_CHG_CUR_175MA:
        return 175;
    case XPOWERS_AXP2101_CHG_CUR_200MA:
        return 200;
    case XPOWERS_AXP2101_CHG_CUR_300MA:
        return 300;
    case XPOWERS_AXP2101_CHG_CUR_400MA:
        return 400;
    case XPOWERS_AXP2101_CHG_CUR_500MA:
        return 500;
    case XPOWERS_AXP2101_CHG_CUR_600MA:
        return 600;
    case XPOWERS_AXP2101_CHG_CUR_700MA:
        return 700;
    case XPOWERS_AXP2101_CHG_CUR_800MA:
        return 800;
    case XPOWERS_AXP2101_CHG_CUR_900MA:
        return 900;
    case XPOWERS_AXP2101_CHG_CUR_1000MA:
        return 1000;
    case XPOWERS_AXP2101_CHG_CUR_1100MA:
        return 1100;
    case XPOWERS_AXP2101_CHG_CUR_1200MA:
        return 1200;
    case XPOWERS_AXP2101_CHG_CUR_1300MA:
        return 1300;
    case XPOWERS_AXP2101_CHG_CUR_1400MA:
        return 1400;
    case XPOWERS_AXP2101_CHG_CUR_1500MA:
        return 1500;
    default:
        return 0;
    }
}

extern "C" uint16_t pmu_get_charge_target_voltage_mv(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }

    switch (s_pmu->getChargeTargetVoltage()) {
    case XPOWERS_AXP2101_CHG_VOL_4V:
        return 4000;
    case XPOWERS_AXP2101_CHG_VOL_4V1:
        return 4100;
    case XPOWERS_AXP2101_CHG_VOL_4V2:
        return 4200;
    case XPOWERS_AXP2101_CHG_VOL_4V35:
        return 4350;
    case XPOWERS_AXP2101_CHG_VOL_4V4:
        return 4400;
    default:
        return 0;
    }
}

extern "C" uint16_t pmu_get_vbus_current_limit_ma(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return 0;
    }

    switch (s_pmu->getVbusCurrentLimit()) {
    case XPOWERS_AXP2101_VBUS_CUR_LIM_100MA:
        return 100;
    case XPOWERS_AXP2101_VBUS_CUR_LIM_500MA:
        return 500;
    case XPOWERS_AXP2101_VBUS_CUR_LIM_900MA:
        return 900;
    case XPOWERS_AXP2101_VBUS_CUR_LIM_1000MA:
        return 1000;
    case XPOWERS_AXP2101_VBUS_CUR_LIM_1500MA:
        return 1500;
    case XPOWERS_AXP2101_VBUS_CUR_LIM_2000MA:
        return 2000;
    default:
        return 0;
    }
}

extern "C" float pmu_get_batt_temperature(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return -999.0f;
    }

    const uint16_t raw = s_pmu->getTsTemperature();
    if (raw == 0) {
        return -999.0f;
    }

    return pmu_validate_batt_temperature(pmu_raw_ts_to_celsius(raw));
}

extern "C" float pmu_get_die_temperature(void)
{
    if (!s_ready || s_pmu == nullptr) {
        return -999.0f;
    }
    return s_pmu->getTemperature();
}
