//
// Created by xin on 25-5-8.
//

#include "sunupanddown.h"
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
bool isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int dayOfYear(int year, int month, int day) {
    int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (isLeapYear(year)) {
        days[2] = 29;
    }
    int sum = day;
    for (int i = 1; i < month; ++i) {
        sum += days[i];
    }
    return sum;
}
void calculateSunriseSunset(int year, int month, int day, double latitude, double longitude,
                            double &sunrise, double &sunset, bool &hasSunlight) {
    int n = dayOfYear(year, month, day);

    // 计算太阳赤纬（单位：度）
    double delta_deg = 23.44 * sin(2 * M_PI * (284.0 + n) / 365.0);
    double delta_rad = delta_deg * M_PI / 180.0;

    // 日出日落时太阳高度角（考虑大气折射）
    double h0_deg = -0.833;
    double h0_rad = h0_deg * M_PI / 180.0;

    // 纬度转换为弧度
    double phi_rad = latitude * M_PI / 180.0;
    double sin_phi = sin(phi_rad);
    double cos_phi = cos(phi_rad);
    double sin_delta = sin(delta_rad);
    double cos_delta = cos(delta_rad);

    // 计算时角的余弦值
    double numerator = sin(h0_rad) - sin_phi * sin_delta;
    double denominator = cos_phi * cos_delta;

    if (denominator == 0) {
        hasSunlight = false;
        return;
    }

    double cos_omega = numerator / denominator;

    if (cos_omega < -1.0 || cos_omega > 1.0) {
        // 极昼或极夜
        hasSunlight = false;
        return;
    }

    // 计算时角并转换为小时
    double omega_rad = acos(cos_omega);
    double omega_deg = omega_rad * 180.0 / M_PI;
    double omega_hours = omega_deg / 15.0;

    // 地方时日出日落时间
    double sunrise_local = 12.0 - omega_hours;
    double sunset_local = 12.0 + omega_hours;

    // 计算时区修正
    double timezone_h = round(longitude / 15.0);
    double timezone_lon = timezone_h * 15.0;
    double time_diff = (longitude - timezone_lon) / 15.0; // 小时

    // 转换为标准时间
    sunrise = sunrise_local - time_diff;
    sunset = sunset_local - time_diff;

    // 处理时间溢出
    sunrise = fmod(sunrise + 24.0, 24.0);
    sunset = fmod(sunset + 24.0, 24.0);

    hasSunlight = true;
}

SunInfo calculateSunriseSunset(int year, int month, int day, double latitude, double longitude){
    SunInfo sunInfo;
    double sunrise, sunset;
    bool hasSunlight;

    calculateSunriseSunset(year, month, day, latitude, longitude, sunrise, sunset, hasSunlight);

    sunInfo.sunrise_h = floor(sunrise);
    sunInfo.sunrise_m = (sunrise - sunInfo.sunrise_h) * 60;
    sunInfo.sunset_h = floor(sunset);
    sunInfo.sunset_m = (sunset - sunInfo.sunset_h) * 60;
    sunInfo.hasSunlight = hasSunlight;

    return sunInfo;
}