#include "common.h"
#include "hardware_iic.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <stdint.h>
#include <pthread.h>

#define I2C_DEVICE "/dev/i2c-2" // 示例：使用 I2C 总线 2

static int s_fd = 0;
static uint8_t s_current_iic_addr = 0; // 记录当前设置的 I2C 地址

static pthread_mutex_t s_i2c_mutex = PTHREAD_MUTEX_INITIALIZER; // I2C 操作互斥锁

int hardware_iic_config_init();

int hardware_iic_init() {
    if(hardware_iic_config_init()!=0){
        return 1;
    }

    // 打开 I2C 设备
    s_fd = open(I2C_DEVICE, O_RDWR);
    if (s_fd < 0) {
        my_zlog_error("错误：无法打开 I2C 设备 %s\n", I2C_DEVICE);
        return 1;
    }
    my_zlog_info("I2C 设备 %s 打开成功。", I2C_DEVICE);
    
    return 0;
}

// 设置 I2C 从设备地址，如果当前地址不同则设置
int set_hardware_iic(uint8_t iic_addr) {
    if (s_fd <= 0) {
        my_zlog_error("I2C 设备未初始化或已关闭。");
        return 1;
    }
    if (s_current_iic_addr != iic_addr) {
        if (ioctl(s_fd, I2C_SLAVE, iic_addr) < 0) {
            my_zlog_warn("错误：无法设置 I2C 地址 0x%02X", iic_addr);
            // close(s_fd); // 不在这里关闭，可能需要重试
            return 1;
        }
        s_current_iic_addr = iic_addr;
        my_zlog_info("I2C 地址设置为 0x%02X。", iic_addr);
    }
    return 0;
}

// 硬件 I2C 写入函数
// device_addr: 从设备地址
// reg_addr: 寄存器地址
// data: 要写入的数据
// len: 数据长度 (不包括寄存器地址)
int hardware_iic_write(uint8_t device_addr, uint8_t reg_addr, const uint8_t *data, int len) {
    // 加锁，确保同一时间只有一个线程访问 I2C
    pthread_mutex_lock(&s_i2c_mutex);
    int ret = 1; // 默认失败
    do{

   
    if (set_hardware_iic(device_addr) != 0) {
        break;
    }

    // 构建发送缓冲区：第一个字节是寄存器地址，后面是数据
    uint8_t write_buf[len + 1];
    write_buf[0] = reg_addr;
    for (int i = 0; i < len; i++) {
        write_buf[i + 1] = data[i];
    }

    if (write(s_fd, write_buf, len + 1) != (len + 1)) {
        my_zlog_warn("错误：向设备 0x%02X 寄存器 0x%02X 写入数据失败。", device_addr, reg_addr);
        break;
    }
        ret = 0; // 成功
    }while(0);
    pthread_mutex_unlock(&s_i2c_mutex);
    // my_zlog_info("成功向设备 0x%02X 寄存器 0x%02X 写入 %d 字节数据。", device_addr, reg_addr, len);
    return ret;
}

// 硬件 I2C 读取函数
// device_addr: 从设备地址
// reg_addr: 寄存器地址
// data: 存储读取数据的缓冲区
// len: 要读取的数据长度
int hardware_iic_read(uint8_t device_addr, uint8_t reg_addr, uint8_t *data, int len) {
    int ret=1;
    pthread_mutex_lock(&s_i2c_mutex);
    do{

    if (set_hardware_iic(device_addr) != 0) {
        break;
    }

    // 先写入要读取的寄存器地址
    if (write(s_fd, &reg_addr, 1) != 1) {
        my_zlog_warn("错误：向设备 0x%02X 设置读取寄存器 0x%02X 失败。", device_addr, reg_addr);
        break;
    }

    // 然后从该寄存器读取数据
    if (read(s_fd, data, len) != len) {
        my_zlog_warn("错误：从设备 0x%02X 寄存器 0x%02X 读取 %d 字节数据失败。", device_addr, reg_addr, len);
        break;
    }

        ret = 0;
    }while(0);

    pthread_mutex_unlock(&s_i2c_mutex);

    // my_zlog_info("成功从设备 0x%02X 寄存器 0x%02X 读取 %d 字节数据。", device_addr, reg_addr, len);
    return ret;
}

int hardware_iic_close() {
    if (s_fd > 0) {
        close(s_fd);
        s_fd = 0;
        s_current_iic_addr = 0;
        my_zlog_info("关闭 I2C 设备。");
    }
    return 0;
}


#define FILE_PATH "/boot/orangepiEnv.txt"
#define TMP_FILE_PATH "/tmp/orangepiEnv.tmp"
#define TARGET_OVERLAY "i2c2-m1"

// 检查字符串是否以指定内容结尾
static bool iic_ends_with(const char *str, const char *suffix) {
    if (!str || !suffix) return false;
    size_t len_str = strlen(str);
    size_t len_suffix = strlen(suffix);
    if (len_suffix > len_str) return false;
    return strncmp(str + len_str - len_suffix, suffix, len_suffix) == 0;
}

// 检查是否包含目标overlay（精确匹配）
static bool contains_target_overlay(const char *overlays_value) {
    if (!overlays_value || strlen(overlays_value) == 0) {
        return false;
    }
    
    // 在字符串开头、逗号之间或结尾精确匹配目标overlay
    char search_pattern1[50], search_pattern2[50], search_pattern3[50];
    snprintf(search_pattern1, sizeof(search_pattern1), "%s,", TARGET_OVERLAY);  // 目标在开头或中间
    snprintf(search_pattern2, sizeof(search_pattern2), ",%s,", TARGET_OVERLAY); // 目标在中间
    snprintf(search_pattern3, sizeof(search_pattern3), ",%s", TARGET_OVERLAY);  // 目标在结尾
    
    // 检查各种情况
    if (strcmp(overlays_value, TARGET_OVERLAY) == 0 ||  // 完全相等
        strncmp(overlays_value, search_pattern1, strlen(search_pattern1)) == 0 ||  // 在开头
        strstr(overlays_value, search_pattern2) != NULL ||  // 在中间
        iic_ends_with(overlays_value, TARGET_OVERLAY)) {  // 在结尾
        // 确保结尾匹配是精确的（前面是逗号或是字符串开头）
        if (iic_ends_with(overlays_value, TARGET_OVERLAY)) {
            size_t target_len = strlen(TARGET_OVERLAY);
            size_t value_len = strlen(overlays_value);
            if (value_len == target_len ||  // 完全相等的情况已经在上面检查过
                (value_len > target_len && overlays_value[value_len - target_len - 1] == ',')) {
                return true;
            }
        } else {
            return true;
        }
    }
    
    return false;
}

static int hardware_iic_config() {
    FILE *file, *tmp_file;
    char line[256];
    bool found_overlays = false;
    bool need_modify = false;
    char overlays_value[256] = "";
    
    my_zlog_info("正在检查文件 %s...", FILE_PATH);
    
    // 第一次扫描：检查是否需要修改
    file = fopen(FILE_PATH, "r");
    if (file == NULL) {
        my_zlog_warn("无法打开文件");
        return 1;
    }
    
    while (fgets(line, sizeof(line), file)) {
        if (strncmp(line, "overlays=", 9) == 0) {
            found_overlays = true;
            // 提取overlays的值（去掉换行符）
            char *value = line + 9;
            value[strcspn(value, "\n\r")] = 0;
            strncpy(overlays_value, value, sizeof(overlays_value) - 1);
            
            if (!contains_target_overlay(value)) {
                need_modify = true;
                my_zlog_info("当前overlays值: %s", value);
                my_zlog_info("需要添加: %s", TARGET_OVERLAY);
            } else {
                my_zlog_info("目标overlay已存在，无需修改");
            }
            break;
        }
    }
    fclose(file);
    
    // 如果没有找到overlays行，也需要修改
    if (!found_overlays) {
        need_modify = true;
        my_zlog_info("未找到overlays行，需要添加");
    }
    
    // 如果不需要修改，直接退出
    if (!need_modify) {
        my_zlog_info("文件无需修改，返回。");
        return 10;
    }
    
    my_zlog_info("开始修改文件...");
    
    // 重新打开文件进行修改
    file = fopen(FILE_PATH, "r");
    if (file == NULL) {
        my_zlog_error("无法打开文件");
        return 1;
    }
    
    tmp_file = fopen(TMP_FILE_PATH, "w");
    if (tmp_file == NULL) {
        my_zlog_error("无法创建临时文件");
        fclose(file);
        return 1;
    }
    
    // 处理文件内容
    bool overlays_processed = false;
    while (fgets(line, sizeof(line), file)) {
        if (strncmp(line, "overlays=", 9) == 0 && !overlays_processed) {
            overlays_processed = true;
            char *value = line + 9;
            value[strcspn(value, "\n\r")] = 0;
            
            if (strlen(value) == 0) {
                // 空overlays
                fprintf(tmp_file, "overlays=%s\n", TARGET_OVERLAY);
            } else {
                // 非空，添加到末尾
                if (value[strlen(value) - 1] == ',') {
                    fprintf(tmp_file, "overlays=%s%s\n", value, TARGET_OVERLAY);
                } else {
                    fprintf(tmp_file, "overlays=%s,%s\n", value, TARGET_OVERLAY);
                }
            }
        } else {
            fputs(line, tmp_file);
        }
    }
    
    // 如果文件中没有overlays行，在文件末尾添加
    if (!overlays_processed) {
        fprintf(tmp_file, "overlays=%s\n", TARGET_OVERLAY);
    }
    
    fclose(file);
    fclose(tmp_file);
    
    // 备份原文件
    char backup_cmd[256];
    snprintf(backup_cmd, sizeof(backup_cmd), "cp %s %s.bak", FILE_PATH, FILE_PATH);
    my_zlog_info("创建备份文件...");
    if (system(backup_cmd) != 0) {
       my_zlog_info("备份文件创建失败");
        remove(TMP_FILE_PATH);
        return 1;
    }
    
    // 替换原文件
    char replace_cmd[256];
    snprintf(replace_cmd, sizeof(replace_cmd), "mv %s %s", TMP_FILE_PATH, FILE_PATH);
    my_zlog_info("更新文件...");
    if (system(replace_cmd) != 0) {
        my_zlog_info("文件更新失败");
        return 1;
    }
    
    my_zlog_info("文件更新完成！原文件已备份为%s.bak", FILE_PATH);
    return 0;
}


int hardware_iic_config_init(){
    int res=hardware_iic_config();
    if(res==10){
        return 0;
    }else if(res ==0){
        delay_ms(200);
        int ret=system("sudo reboot");//重启香橙派
        if(ret==0) my_zlog_info("重启成功");
        return 1;
    }
}
