#include "rtc_aip8563.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include <string.h>
#include <stdbool.h>

#define AIP8563_I2C_ADDR 0x51      // Aip8563的7位I2C地址
#define AIP8563_REG_SEC  0x02      // 秒寄存器地址
#define TAG "AIP8563"

// BCD与十进制转换工具函数
static uint8_t bcd2bin(uint8_t val) { return ((val >> 4) * 10) + (val & 0x0F); }
static uint8_t bin2bcd(uint8_t val) { return ((val / 10) << 4) | (val % 10); }

// RTC初始化：仅在VL=1（掉电）时才设置默认时间，否则不重置
esp_err_t rtc_aip8563_init(void)
{
    uint8_t reg = AIP8563_REG_SEC;
    uint8_t sec = 0;
    // 读取秒寄存器，判断VL位
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (AIP8563_I2C_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg, true);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(1, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Read VL check reg failed: %s", esp_err_to_name(ret));
        return ret;
    }
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (AIP8563_I2C_ADDR << 1) | I2C_MASTER_READ, true);
    i2c_master_read(cmd, &sec, 1, I2C_MASTER_LAST_NACK);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(1, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Read VL check value failed: %s", esp_err_to_name(ret));
        return ret;
    }
    // 只在VL=1（掉电）时重置时间
    if (sec & 0x80) {
        ESP_LOGW(TAG, "RTC VL=1, set default time");
        rtc_time_t default_time = {
            .year = 25,      // 2025年
            .month = 1,      // 1月
            .day = 1,        // 1日
            .hour = 8,       // 8点
            .minute = 0,     // 0分
            .second = 0,     // 0秒
            .weekday = 3     // 星期三
        };
        return rtc_aip8563_set_time(&default_time);
    }
    return ESP_OK;
}

// 读取RTC当前时间
esp_err_t rtc_aip8563_get_time(rtc_time_t *time)
{
    uint8_t reg = AIP8563_REG_SEC; // 从秒寄存器开始读
    uint8_t data[7] = {0};         // 用于接收7字节时间数据

    // 1. 先写寄存器地址，指向秒寄存器
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (AIP8563_I2C_ADDR << 1) | I2C_MASTER_WRITE, true); // 发送写地址
    i2c_master_write_byte(cmd, reg, true); // 发送寄存器地址
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(1, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Write reg failed: %s", esp_err_to_name(ret));
        return ret;
    }

    // 2. 读7字节时间数据
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (AIP8563_I2C_ADDR << 1) | I2C_MASTER_READ, true); // 发送读地址
    i2c_master_read(cmd, data, 7, I2C_MASTER_LAST_NACK); // 读7字节
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(1, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Read time failed: %s", esp_err_to_name(ret));
        return ret;
    }

    // 3. 解析BCD数据为十进制
    time->second  = bcd2bin(data[0] & 0x7F); // bit7为VL标志
    time->minute  = bcd2bin(data[1] & 0x7F);
    time->hour    = bcd2bin(data[2] & 0x3F);
    time->day     = bcd2bin(data[3] & 0x3F);
    time->weekday = bcd2bin(data[4] & 0x07);
    time->month   = bcd2bin(data[5] & 0x1F);
    time->year    = bcd2bin(data[6]);
    return ESP_OK;
}

// 设置RTC时间
esp_err_t rtc_aip8563_set_time(const rtc_time_t *time)
{
    uint8_t data[8];
    data[0] = AIP8563_REG_SEC; // 起始寄存器地址
    data[1] = bin2bcd(time->second);
    data[2] = bin2bcd(time->minute);
    data[3] = bin2bcd(time->hour);
    data[4] = bin2bcd(time->day);
    data[5] = bin2bcd(time->weekday);
    data[6] = bin2bcd(time->month);
    data[7] = bin2bcd(time->year);

    // 1. 发送写命令和7字节时间数据
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (AIP8563_I2C_ADDR << 1) | I2C_MASTER_WRITE, true); // 发送写地址
    i2c_master_write(cmd, data, 8, true); // 发送寄存器地址+7字节数据
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(1, cmd, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Set time failed: %s", esp_err_to_name(ret));
    }
    return ret;
}

// ========== LVGL缓存机制 ========== //
// RTC时间缓存
static rtc_time_t g_rtc_cache;
static bool g_rtc_cache_valid = false;
// LVGL设置时间时的写缓存和写标志
static bool g_rtc_need_write = false;
static rtc_time_t g_rtc_write_buf;

// LVGL获取时间接口，只读缓存
int get_rtc_get_time(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second, uint8_t *weekday)
{
    if (!g_rtc_cache_valid) return -1; // 缓存无效
    if (year)    *year    = g_rtc_cache.year;
    if (month)   *month   = g_rtc_cache.month;
    if (day)     *day     = g_rtc_cache.day;
    if (hour)    *hour    = g_rtc_cache.hour;
    if (minute)  *minute  = g_rtc_cache.minute;
    if (second)  *second  = g_rtc_cache.second;
    if (weekday) *weekday = g_rtc_cache.weekday;
    return 0;
}

// LVGL设置时间接口，只写缓存，设置写标志
int set_rtc_set_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint8_t weekday)
{
    g_rtc_write_buf.year    = year;
    g_rtc_write_buf.month   = month;
    g_rtc_write_buf.day     = day;
    g_rtc_write_buf.hour    = hour;
    g_rtc_write_buf.minute  = minute;
    g_rtc_write_buf.second  = second;
    g_rtc_write_buf.weekday = weekday;
    g_rtc_need_write = true; // 标记有新的时间需要写入RTC
    return 0;
}

// 获取当前时间
int rtc_get_time(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second, uint8_t *weekday)
{
    rtc_time_t t;
    if (rtc_aip8563_get_time(&t) != ESP_OK) return -1;
    // 刷新缓存
    g_rtc_cache = t;
    g_rtc_cache_valid = true;  //表示缓存中的数据有效，可能被读取
    
    // 安全的NULL指针检查，只在指针不为NULL时才赋值
    if (year) *year = t.year;
    if (month) *month = t.month;
    if (day) *day = t.day;
    if (hour) *hour = t.hour;
    if (minute) *minute = t.minute;
    if (second) *second = t.second;
    if (weekday) *weekday = t.weekday;
    return 0;
}

// 设置当前时间
int rtc_set_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint8_t weekday)
{
    rtc_time_t t = {
        .year = year,
        .month = month,
        .day = day,
        .hour = hour,
        .minute = minute,
        .second = second,
        .weekday = weekday
    };
    int ret = (rtc_aip8563_set_time(&t) == ESP_OK) ? 0 : -1;
    if (ret == 0) {
        g_rtc_need_write = false; // 写入成功后，清除写入标志
    }
    return ret;
}

// 获取是否需要写入RTC的标志
bool rtc_need_write_flag(void) {
    return g_rtc_need_write;
}

// 执行待写入的RTC数据写入操作，主循环调用
int rtc_write_pending_time(void) {
    if (!g_rtc_need_write) {
        return 0; // 没有待写入的数据
    }
    
    int ret = rtc_set_time(g_rtc_write_buf.year, g_rtc_write_buf.month, g_rtc_write_buf.day, 
                          g_rtc_write_buf.hour, g_rtc_write_buf.minute, g_rtc_write_buf.second, 
                          g_rtc_write_buf.weekday);
    return ret;
}

// ========== 自动weekday计算功能 ========== //

/**
 * 使用蔡勒公式计算星期几
 * @param year  年份（00-99，表示20xx年）
 * @param month 月份（1-12）
 * @param day   日期（1-31）
 * @return weekday（0=周日，1=周一，2=周二，3=周三，4=周四，5=周五，6=周六）
 */
uint8_t rtc_calculate_weekday(uint8_t year, uint8_t month, uint8_t day)
{
    // 将年份转换为完整年份（假设输入是20xx年的后两位）
    int full_year = 2000 + year;
    int q = day;
    int m = month;
    int K = full_year % 100;  // 年份的后两位
    int J = full_year / 100;  // 年份的前两位
    
    // 蔡勒公式中1月和2月要按照前一年的13月和14月来计算
    if (m <= 2) {
        m += 12;
        full_year--;
        K = full_year % 100;
        J = full_year / 100;
    }
    
    // 蔡勒公式: w = (q + [(13*(m+1))/5] + K + [K/4] + [J/4] - 2*J) mod 7
    int w = (q + (13 * (m + 1)) / 5 + K + K / 4 + J / 4 - 2 * J) % 7;
    
    // 蔡勒公式结果：0=周六，1=周日，2=周一，...，6=周五
    // 转换为我们需要的格式：0=周日，1=周一，...，6=周六
    int weekday = (w + 6) % 7;
    
    ESP_LOGD(TAG, "Calculate weekday: %d/%d/%d -> weekday=%d", full_year, month, day, weekday);
    return (uint8_t)weekday;
}

/**
 * 自动计算weekday并设置RTC时间
 */
int rtc_set_time_auto_weekday(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
    uint8_t weekday = rtc_calculate_weekday(year, month, day);
    return rtc_set_time(year, month, day, hour, minute, second, weekday);
}

/**
 * 测试函数：验证weekday计算的正确性
 * 可在初始化时调用来验证算法
 */
void rtc_test_weekday_calculation(void)
{
    // 测试一些已知日期
    struct {
        uint8_t year, month, day;
        uint8_t expected_weekday;
        const char* date_str;
        const char* day_name;
    } test_cases[] = {
        {25, 7, 20, 0, "2025-07-20", "周日"},  // 用户提供的例子
        {25, 1, 1,  3, "2025-01-01", "周三"},  // 2025年元旦
        {24, 12, 25, 3, "2024-12-25", "周三"}, // 2024年圣诞节
        {24, 2, 29, 4, "2024-02-29", "周四"},  // 2024年闰年2月29日
        {25, 12, 31, 3, "2025-12-31", "周三"}, // 2025年最后一天
    };
    
    ESP_LOGI(TAG, "=== RTC Weekday Calculation Test ===");
    
    for (int i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
        uint8_t calculated = rtc_calculate_weekday(test_cases[i].year, test_cases[i].month, test_cases[i].day);
        bool correct = (calculated == test_cases[i].expected_weekday);
        
        ESP_LOGI(TAG, "Test %d: %s (%s) - Expected: %d, Got: %d %s", 
                i + 1, 
                test_cases[i].date_str,
                test_cases[i].day_name,
                test_cases[i].expected_weekday, 
                calculated,
                correct ? "✓" : "✗");
    }
    
    ESP_LOGI(TAG, "Weekday mapping: 0=周日, 1=周一, 2=周二, 3=周三, 4=周四, 5=周五, 6=周六");
    ESP_LOGI(TAG, "=== Test Complete ===");
} 