#include "rtc.h"
#include "main.h"
#include "RTCtime.h"
#include <time.h>

#define FOURYEARDAY (365+365+365+366)  //4年一个周期内的总天数（1970~2038不存在2100这类年份，故暂不优化）
#define TIMEZONE    (8)                //北京时区调整 
extern RTC_HandleTypeDef hrtc;


// 月份对应的天数（非闰年）
const uint8_t month_day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 闰年时的月份对应的天数
const uint8_t Leap_month_day[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// 判断是否为闰年
uint8_t isLeapYear(uint16_t year)
{
    return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 1 : 0;
}

/**
 * @brief 从4G接收缓冲区中提取+CCLK时间并转换为世纪秒
 * @param buffer 接收缓冲区内容
 * @return 成功返回世纪秒（time_t类型），失败返回-1
 */
char time_str[50];
time_t parse_cclk_time(const char *buffer)
{
    // 查找+CCLK行
    const char *cclk_line = strstr(buffer, "+CCLK:");
    if (!cclk_line) {
        printf("Not found +CCLK \n");
        return 2;
    }

    // 查找时间字符串的起始和结束位置
    const char *quote_start = strchr(cclk_line, '"');
    if (!quote_start) {
        printf("Not found ""\n");
        return 2;
    }
    const char *quote_end = strchr(quote_start + 1, '"');
    if (!quote_end) {
        printf("Not found ""\n");
        return 2;
    }

    // 提取时间字符串

    size_t time_len = quote_end - quote_start - 1;
    strncpy(time_str, quote_start + 1, time_len);
    time_str[time_len] = '\0';

    // 分离时间和时区部分
    char *tz_pos = strpbrk(time_str, "+-");
    if (tz_pos) {
        *tz_pos = '\0'; // 截断时区部分
    }

    // 解析日期时间
    struct tm tm = {0};
    int yy, mm, dd, hh, min, sec;
    if (sscanf(time_str, "%d/%d/%d,%d:%d:%d", 
               &yy, &mm, &dd, &hh, &min, &sec) != 6) {
        printf("Parsing_unix_failed\n");
        return 2;
    }

    // 填充struct tm结构体
    tm.tm_year = yy + 100; // 2025年表示为125
    tm.tm_mon = mm - 1;    // 月份0-11
    tm.tm_mday = dd;
    tm.tm_hour = hh;
    tm.tm_min = min;
    tm.tm_sec = sec;
    tm.tm_isdst = 2;      // 自动判断夏令时

    // 转换为世纪秒
    time_t epoch_time = mktime(&tm);
    if (epoch_time == 2) {
        printf("Conversion failed\n");
        return 2;
    }

    return epoch_time;
}

/**
 * @brief 从WIFI接收缓冲区中提取+CCLK时间并转换为世纪秒
 * @param buffer 接收缓冲区内容
 * @return 成功返回世纪秒（time_t类型），失败返回-1
 */
time_t Parse_WIFI_Time_To_Epoch(const char *response)
{
    struct tm timeinfo = {0};
    int year, month, day, hour, minute, second;

    // 查找 "+TIME:" 开始的位置
    const char *time_start = strstr(response, "+TIME:");
    if (time_start == NULL) {
        return 0;  // 未找到，返回 0
    }

    // 跳过 "+TIME:"
    time_start += strlen("+TIME:");

    // 格式提取：2025-04-22,15:07:56
    if (sscanf(time_start, "%d-%d-%d,%d:%d:%d",
               &year, &month, &day, &hour, &minute, &second) != 6) {
        return 0;  // 解析失败
    }

    timeinfo.tm_year = year - 1900;  // 年份从 1900 开始计
    timeinfo.tm_mon = month - 1;     // 月份从 0 开始计
    timeinfo.tm_mday = day;
    timeinfo.tm_hour = hour;
    timeinfo.tm_min = minute;
    timeinfo.tm_sec = second;

    // 本地时间转为时间戳（北京时间）
    time_t epoch = mktime(&timeinfo); // mktime默认是本地时区，自带处理时区。

    return epoch;
}
/**
 * @brief  将Unix时间戳转换为北京时间
 * @unixTime	 需要判断的Unix时间戳
 * @*tempBeijing	 返回的北京时间
 * @param  Unix时间戳（从1970/1/1 00:00:00 到现在的秒数)
 */
void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing)
{
    uint32_t totleDayNum=0, totleSecNum=0;
    uint16_t remainDayofYear=0, tempYear=0;//, tempDay=0
//    uint8_t *pr=NULL;
	const uint8_t *pr = NULL;
    
    totleDayNum = unixTime/(24*60*60); //总天数(注意加括号)
    totleSecNum = unixTime%(24*60*60); //当天剩余的秒速
 
    memset(tempBeijing, 0x00, sizeof(rtc_time_t));
    
    // 1.先计算时间 HH:MM:SS
    tempBeijing->ui8Hour = totleSecNum/3600;
    tempBeijing->ui8Minute = (totleSecNum%3600)/60; //error：变量搞错
    tempBeijing->ui8Second = (totleSecNum%3600)%60;
 
    // 2.对时间进行时区调整（注意：这里可能造成日期 +1）
    tempBeijing->ui8Hour +=TIMEZONE; 
    if(tempBeijing->ui8Hour>23){
        //printf("modify day..\n");
        tempBeijing->ui8Hour -= 24;
        remainDayofYear++;  // 日期+1
    }
 
    // 3.计算哪一年
    tempBeijing->ui8Year = 1970 + (totleDayNum / FOURYEARDAY) * 4;   // 4年为一个周期
    remainDayofYear += totleDayNum % FOURYEARDAY;
    
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear);
    tempYear = isLeapYear(tempBeijing->ui8Year)?366:365;
    while(remainDayofYear >= tempYear)  // 计算4年整数倍外的年。
    {
        tempBeijing->ui8Year++;
        remainDayofYear -= tempYear;
        tempYear = isLeapYear(tempBeijing->ui8Year)?366:365;
    }
    
    // 4.计算哪一月的哪一天
		
    pr = isLeapYear(tempBeijing->ui8Year)?Leap_month_day:month_day;
    remainDayofYear++;          // 这里开始计算具体日期。remainDayofYear为 0 时其实是 1 号，所以这里要 +1
    while(remainDayofYear > *(pr+tempBeijing->ui8Month))
    {
		remainDayofYear -= *(pr+tempBeijing->ui8Month);
        tempBeijing->ui8Month++;
    }
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear);
    tempBeijing->ui8Month++; //month
    tempBeijing->ui8DayOfMonth = remainDayofYear;  //day
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, tempBeijing->ui8DayOfMonth);
}

/**
 * @brief  将北京时间转换为Unix时间戳
 * @year	 需要判断的年
 * @param  Unix时间戳（从1970/1/1 00:00:00 到现在的秒数)
 */
uint32_t covBeijing2UnixTimeStp(rtc_time_t *beijingTime)
{
	uint32_t daynum=0, SecNum=0; //保存北京时间到起始时间的天数
	uint16_t tempYear=1970, tempMonth=0;
 
 
	//1.年的天数 
	while(tempYear < beijingTime->ui8Year) 
	{
		if(isLeapYear(tempYear)){
			daynum += 366;
		}
		else{
			daynum += 365;
		}
		tempYear++;
	}
	//2.月的天数
 	while(tempMonth < beijingTime->ui8Month-1) 
 	{
        if(isLeapYear(beijingTime->ui8Year)){ //闰年
            daynum += Leap_month_day[tempMonth];
        }
        else{
		    daynum += month_day[tempMonth];
        }
		tempMonth++;
	}
  //3.天数
	daynum += (beijingTime->ui8DayOfMonth-1);
 
	//4.时分秒
	SecNum = daynum*24*60*60; //s    
	SecNum += beijingTime->ui8Hour*60*60;    
	SecNum += beijingTime->ui8Minute*60;    
	SecNum += beijingTime->ui8Second;

	//5.时区调整
	SecNum -= TIMEZONE*60*60;

	return SecNum;
}

/**
 * @brief  设置 RTC 时间
 * @param  epoch_time 需要设置的世纪秒时间
 */
void Set_RTC_Time(time_t epoch_time)
{
    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef sDate = {0};
    rtc_time_t beijingTime;
    
    // 转换 Unix 时间戳到 RTC 结构体
    covUnixTimeStp2Beijing(epoch_time, &beijingTime);

    // 设置 RTC 时间
    sTime.Hours   = beijingTime.ui8Hour;
    sTime.Minutes = beijingTime.ui8Minute;
    sTime.Seconds = beijingTime.ui8Second;
    sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    sTime.StoreOperation = RTC_STOREOPERATION_RESET;

    // 设置 RTC 日期
    sDate.Year  = beijingTime.ui8Year - 2000;  // STM32 的 RTC 年份从 2000 开始
    sDate.Month = beijingTime.ui8Month;
    sDate.Date  = beijingTime.ui8DayOfMonth;
    sDate.WeekDay = RTC_WEEKDAY_MONDAY;  // 这里不计算星期几，设为默认值

    // 写入 RTC
    if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
    {
        Error_Handler();
    }
    if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief  获取 RTC 时间并转换为世纪秒
 * @return 返回当前 RTC 时间的 time_t 值
 */
time_t Get_RTC_Time(void)
{
    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef sDate = {0};
    rtc_time_t beijingTime;

    // 读取 RTC 时间和日期
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

    // 转换为 `rtc_time_t` 结构体
    beijingTime.ui8Year = sDate.Year + 2000;
    beijingTime.ui8Month = sDate.Month;
    beijingTime.ui8DayOfMonth = sDate.Date;
    beijingTime.ui8Hour = sTime.Hours;
    beijingTime.ui8Minute = sTime.Minutes;
    beijingTime.ui8Second = sTime.Seconds;

    // 转换为 Unix 时间戳
    return covBeijing2UnixTimeStp(&beijingTime);
}

void printCurrentRTCTime(void)
{
    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef sDate = {0};
    char timeString[20];  // 用于存储格式化的时间字符串
		char dataString[20];  // 用于存储格式化的时间字符串

    // 获取当前时间
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    
    // 获取当前日期
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

    // 格式化时间为字符串 "HH:MM:SS"
    snprintf(timeString, sizeof(timeString), "%02d:%02d:%02d", 
             sTime.Hours, sTime.Minutes, sTime.Seconds); 
    // 格式化日期为字符串 "YYYY/MM/DD"
    snprintf(dataString, sizeof(dataString), "20%02d/%02d/%02d", 
             sDate.Year, sDate.Month, sDate.Date);

    // 打印日期
    printf("RTC %s-%s\n", dataString, timeString);
}
