import math
import customtkinter as ctk
from datetime import datetime
from tkinter import messagebox

# Konfigurasi Tema Utama
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")

class AstroCalcApp(ctk.CTk):
    def __init__(self):
        super().__init__()

        self.title("AstroCalc Pro - Modern Edition")
        self.geometry("550x700")
        
        # Konfigurasi Grid Utama agar responsif
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        # --- Frame Utama dengan Fitur Scroll ---
        self.main_scroll = ctk.CTkScrollableFrame(self, corner_radius=0, fg_color="transparent")
        self.main_scroll.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
        self.main_scroll.grid_columnconfigure(0, weight=1)

        # --- Header ---
        self.header_frame = ctk.CTkFrame(self.main_scroll, fg_color="transparent")
        self.header_frame.pack(pady=(30, 20))
        
        self.header_label = ctk.CTkLabel(self.header_frame, text="ASTROCALC PRO", 
                                        font=ctk.CTkFont(size=28, weight="bold"))
        self.header_label.pack()
        
        self.sub_header = ctk.CTkLabel(self.header_frame, text="Solusi Astronomi Presisi Tinggi", 
                                       text_color="#3b8ed0", font=ctk.CTkFont(size=14))
        self.sub_header.pack()

        # --- Bagian Input ---
        self.container_input = ctk.CTkFrame(self.main_scroll)
        self.container_input.pack(pady=10, padx=30, fill="x")

        self.create_label_input(self.container_input, "Tanggal Pengamatan (YYYY-MM-DD):", 
                                datetime.now().strftime("%Y-%m-%d"), "entry_date")
        self.create_label_input(self.container_input, "Garis Lintang (Latitude):", "-7.0", "entry_lat")
        self.create_label_input(self.container_input, "Garis Bujur (Longitude):", "110.4", "entry_lon")
        self.create_label_input(self.container_input, "Zona Waktu (GMT Offset):", "7", "entry_tz")

        # Tombol Analisis
        self.btn_calculate = ctk.CTkButton(self.main_scroll, text="MULAI ANALISIS DATA", 
                                           command=self.process_calculation, height=50, 
                                           font=ctk.CTkFont(size=15, weight="bold"),
                                           corner_radius=10)
        self.btn_calculate.pack(pady=25, padx=30, fill="x")

        # --- Bagian Hasil (Grid Card) ---
        self.result_container = ctk.CTkFrame(self.main_scroll, fg_color="transparent")
        self.result_container.pack(pady=(0, 40), padx=30, fill="x")
        self.result_container.grid_columnconfigure((0, 1), weight=1)

        self.res_sunrise = self.create_card(self.result_container, "MATAHARI TERBIT", "00:00", 0, 0)
        self.res_sunset = self.create_card(self.result_container, "MATAHARI TERBENAM", "00:00", 0, 1)
        self.res_day = self.create_card(self.result_container, "DURASI SIANG", "0j 0m", 1, 0)
        self.res_night = self.create_card(self.result_container, "DURASI MALAM", "0j 0m", 1, 1)

    def create_label_input(self, parent, text, placeholder, attr_name):
        lbl = ctk.CTkLabel(parent, text=text, font=ctk.CTkFont(size=12, weight="bold"))
        lbl.pack(pady=(15, 0), padx=25, anchor="w")
        
        entry = ctk.CTkEntry(parent, placeholder_text=placeholder, height=35)
        entry.pack(pady=(5, 10), padx=20, fill="x")
        if attr_name == "entry_date": entry.insert(0, placeholder)
        setattr(self, attr_name, entry)

    def create_card(self, parent, label, value, row, col):
        card = ctk.CTkFrame(parent, corner_radius=15, border_width=1, border_color="#3b8ed0")
        card.grid(row=row, column=col, padx=8, pady=8, sticky="nsew")
        
        lbl = ctk.CTkLabel(card, text=label, font=ctk.CTkFont(size=10, weight="bold"), text_color="gray")
        lbl.pack(pady=(15, 0))
        
        val = ctk.CTkLabel(card, text=value, font=ctk.CTkFont(size=20, weight="bold"))
        val.pack(pady=(0, 15))
        return val

    def calculate_logic(self, lat, lon, tz, date_str):
        try:
            date_obj = datetime.strptime(date_str, "%Y-%m-%d")
            rad, deg = math.pi / 180, 180 / math.pi
            jd = (date_obj.timestamp() / 86400.0) + 2440587.5
            d = jd - 2451545.0
            g = (357.529 + 0.98560028 * d) % 360
            q = (280.459 + 0.98564736 * d) % 360
            L = (q + 1.915 * math.sin(g * rad) + 0.020 * math.sin(2 * g * rad)) % 360
            e = 23.439 - 0.00000036 * d
            dec_rad = math.asin(math.sin(e * rad) * math.sin(L * rad))
            ra = (math.atan2(math.cos(e * rad) * math.sin(L * rad), math.cos(L * rad)) * deg + 360) % 360
            eqt = (q / 15.0) - (ra / 15.0)
            h_rad, lat_rad = -0.8333 * rad, lat * rad
            cos_t = (math.sin(h_rad) - math.sin(lat_rad) * math.sin(dec_rad)) / (math.cos(lat_rad) * math.cos(dec_rad))

            if cos_t > 1: return "Polar Night"
            if cos_t < -1: return "Midnight Sun"

            t_hour = (math.acos(cos_t) * deg) / 15.0
            transit = 12 + tz - (lon / 15.0) - eqt
            
            return {
                "sunrise": (transit - t_hour + 24) % 24,
                "sunset": (transit + t_hour + 24) % 24,
                "day": t_hour * 2,
                "night": 24 - (t_hour * 2)
            }
        except: return None

    def format_time(self, decimal_hours):
        hrs = int(decimal_hours)
        mins = round((decimal_hours - hrs) * 60)
        if mins == 60: hrs += 1; mins = 0
        return f"{hrs:02d}:{mins:02d}"

    def process_calculation(self):
        try:
            res = self.calculate_logic(float(self.entry_lat.get()), float(self.entry_lon.get()), 
                                      float(self.entry_tz.get()), self.entry_date.get())
            if res in ["Polar Night", "Midnight Sun"]:
                messagebox.showinfo("Info", res)
            elif res:
                self.res_sunrise.configure(text=self.format_time(res['sunrise']))
                self.res_sunset.configure(text=self.format_time(res['sunset']))
                self.res_day.configure(text=f"{int(res['day'])}j {round((res['day']%1)*60)}m")
                self.res_night.configure(text=f"{int(res['night'])}j {round((res['night']%1)*60)}m")
            else:
                messagebox.showerror("Error", "Gagal menghitung data!")
        except ValueError:
            messagebox.showerror("Error", "Harap masukkan angka yang valid!")

if __name__ == "__main__":
    app = AstroCalcApp()
    app.mainloop()