import os, datetime, math, urllib.request, ssl
import numpy as np
import customtkinter as ctk
from tkinter import messagebox
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from skyfield.api import Loader, wgs84

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

def download_custom_file(filename, url):
    filepath = os.path.join(BASE_DIR, filename)
    if not os.path.exists(filepath):
        try:
            req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
            with urllib.request.urlopen(req) as response, open(filepath, 'wb') as out_file:
                out_file.write(response.read())
        except Exception as e: print(f"Gagal mengunduh {filename}: {e}")

class Menu11App(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title("Qiblah Direction & Times (Modul 11)")
        self.geometry("900x600")
        ctk.set_appearance_mode("Dark")
        
        try: _create_unverified_https_context = ssl._create_unverified_context
        except AttributeError: pass
        else: ssl._create_default_https_context = _create_unverified_https_context
        
        self.load_obj = Loader(BASE_DIR)
        self.eph = self.load_obj('de421.bsp')
        self.ts = self.load_obj.timescale()
        self.setup_ui()

    def setup_ui(self):
        self.sidebar = ctk.CTkFrame(self, width=250)
        self.sidebar.pack(side="left", fill="y", padx=10, pady=10)
        
        now = datetime.datetime.now()
        ctk.CTkLabel(self.sidebar, text="QIBLAH DIRECTION", font=("Segoe UI", 16, "bold")).pack(pady=20)
        
        self.entry_y = ctk.CTkEntry(self.sidebar, placeholder_text="Tahun"); self.entry_y.insert(0, str(now.year)); self.entry_y.pack(pady=5)
        self.entry_m = ctk.CTkEntry(self.sidebar, placeholder_text="Bulan"); self.entry_m.insert(0, str(now.month)); self.entry_m.pack(pady=5)
        self.entry_d = ctk.CTkEntry(self.sidebar, placeholder_text="Tanggal"); self.entry_d.insert(0, str(now.day)); self.entry_d.pack(pady=5)
        
        self.entry_lat = ctk.CTkEntry(self.sidebar, placeholder_text="Latitude"); self.entry_lat.insert(0, "-7.0667"); self.entry_lat.pack(pady=5)
        self.entry_lon = ctk.CTkEntry(self.sidebar, placeholder_text="Longitude"); self.entry_lon.insert(0, "110.4100"); self.entry_lon.pack(pady=5)
        self.entry_tz = ctk.CTkEntry(self.sidebar, placeholder_text="Timezone"); self.entry_tz.insert(0, "7.0"); self.entry_tz.pack(pady=5)
        
        self.radio_var = ctk.StringVar(value="sun")
        ctk.CTkRadioButton(self.sidebar, text="Sun is at Qiblah", variable=self.radio_var, value="sun").pack(pady=5)
        ctk.CTkRadioButton(self.sidebar, text="Shadow is at Qiblah", variable=self.radio_var, value="shadow").pack(pady=5)
        
        ctk.CTkButton(self.sidebar, text="▶ HITUNG WAKTU", command=self.hitung).pack(pady=10)
        ctk.CTkButton(self.sidebar, text="🗺️ TAMPILKAN PETA", fg_color="#00695C", command=self.show_map).pack(pady=5)
        
        self.textbox = ctk.CTkTextbox(self, font=("Consolas", 14))
        self.textbox.pack(side="right", fill="both", expand=True, padx=10, pady=10)

    def hitung(self):
        self.textbox.delete("1.0", "end")
        y, m, d = int(self.entry_y.get()), int(self.entry_m.get()), int(self.entry_d.get())
        lat, lon, tz = float(self.entry_lat.get()), float(self.entry_lon.get()), float(self.entry_tz.get())
        
        # Hitung Azimut Kiblat
        phi_k, lam_k = math.radians(21.4225), math.radians(39.8262)
        phi, lam = math.radians(lat), math.radians(lon)
        y_q = math.sin(lam_k - lam)
        x_q = math.cos(phi)*math.tan(phi_k) - math.sin(phi)*math.cos(lam_k-lam)
        qiblah_angle = (math.degrees(math.atan2(y_q, x_q)) + 360.0) % 360.0
        
        target_az = qiblah_angle if self.radio_var.get() == "sun" else (qiblah_angle + 180.0) % 360.0
        
        t0 = self.ts.utc(y, m, d, -int(tz))
        t1 = self.ts.utc(y, m, d, 24 - int(tz))
        tt_array = np.linspace(t0.tt, t1.tt, 1440)
        
        obs = (self.eph['earth'] + wgs84.latlon(lat, lon)).at(self.ts.tt_jd(tt_array)).observe(self.eph['sun']).apparent()
        alt_arr, az_arr, _ = obs.altaz()
        
        diffs = (az_arr.degrees - target_az + 180.0) % 360.0 - 180.0
        crossings = []
        for i in range(len(diffs) - 1):
            if (diffs[i] <= 0 and diffs[i+1] > 0) or (diffs[i] >= 0 and diffs[i+1] < 0):
                if abs(diffs[i] - diffs[i+1]) < 180.0 and alt_arr.degrees[i] > 0:
                    frac = abs(diffs[i]) / (abs(diffs[i]) + abs(diffs[i+1]) + 1e-9)
                    tt_res = tt_array[i] + frac * (tt_array[i+1] - tt_array[i])
                    crossings.append(self.ts.tt_jd(tt_res))
                    
        time_1, time_2 = "----", "----"
        if len(crossings) > 0: time_1 = (crossings[0].utc_datetime() + datetime.timedelta(hours=tz)).strftime("%H:%M:%S")
        if len(crossings) > 1: time_2 = (crossings[1].utc_datetime() + datetime.timedelta(hours=tz)).strftime("%H:%M:%S")
        
        self.textbox.insert("end", f"QIBLAH DIRECTION & TIMES\n{'='*60}\n")
        self.textbox.insert("end", f"Arah Kiblat (True North): {qiblah_angle:.2f}°\n")
        self.textbox.insert("end", f"Mode Waktu: {'Matahari di Arah Kiblat' if self.radio_var.get()=='sun' else 'Bayangan di Arah Kiblat'}\n")
        self.textbox.insert("end", f"{'-'*60}\nTanggal       Waktu 1       Waktu 2\n")
        self.textbox.insert("end", f"{d:02d}/{m:02d}/{y}    {time_1}      {time_2}\n")

    def show_map(self):
        try:
            map_file = "map_topografi.jpg" 
            download_custom_file(map_file, "https://hisabmu.com/aifikih/berbagi/map_topografi.jpg")
            
            lons = np.linspace(-180, 180, 360)
            lats = np.linspace(-90, 90, 180)
            LONS, LATS = np.meshgrid(lons, lats)
            
            phi_k, lam_k = math.radians(21.4225), math.radians(39.8262)
            phi, lam = np.radians(LATS), np.radians(LONS)
            
            y = np.sin(lam_k - lam)
            x = np.cos(phi) * np.tan(phi_k) - np.sin(phi) * np.cos(lam_k - lam)
            Q = (np.degrees(np.arctan2(y, x)) + 360) % 360
            
            fig, ax = plt.subplots(figsize=(10, 5))
            if os.path.exists(map_file):
                from PIL import Image
                ax.imshow(Image.open(map_file), extent=[-180, 180, -90, 90], aspect='auto')
            
            ax.contour(LONS, LATS, Q, levels=np.arange(0, 361, 10), colors='black', linewidths=0.6, alpha=0.8)
            ax.scatter(39.8262, 21.4225, color='black', marker='*', s=200, label='Makkah (Kaaba)')
            ax.set_title("Qiblah World Map")
            ax.grid(True)
            ax.legend()
            plt.show()
        except Exception as e:
            messagebox.showerror("Error", str(e))

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