import tkinter as tk
from tkinter import messagebox, filedialog
import customtkinter as ctk
import requests
import json
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
from matplotlib.figure import Figure
import time
from PIL import Image, ImageTk
import io
import base64

class WeatherApp:
    def _init_(self):
        self.window = ctk.CTk()
        self.window.title("Application Météo")
        self.window.geometry("1200x800")
        
        # Dictionnaire des icônes météo (en ASCII art simple)
        self.weather_icons = {
            "clear": "☀️",
            "partly_cloudy": "⛅",
            "cloudy": "☁️",
            "fog": "🌫️",
            "rain": "🌧️",
            "snow": "❄️",
            "storm": "⛈️"
        }
        
        self.weather_codes = {
            0: ("Ciel clair", "clear"),
            1: ("Principalement clair", "clear"),
            2: ("Partiellement nuageux", "partly_cloudy"),
            3: ("Nuageux", "cloudy"),
            45: ("Brouillard", "fog"),
            48: ("Brouillard givrant", "fog"),
            51: ("Bruine légère", "rain"),
            53: ("Bruine modérée", "rain"),
            55: ("Bruine dense", "rain"),
            61: ("Pluie faible", "rain"),
            63: ("Pluie modérée", "rain"),
            65: ("Pluie forte", "rain"),
            71: ("Chute de neige faible", "snow"),
            73: ("Chute de neige modérée", "snow"),
            75: ("Chute de neige dense", "snow"),
            95: ("Orage", "storm"),
            96: ("Orage avec légère grêle", "storm"),
            99: ("Orage avec grêle forte", "storm")
        }
        
        ctk.set_appearance_mode("dark")
        ctk.set_default_color_theme("blue")

        self.weather_data = {}
        self.setup_ui()
        self.update_clock()

    def setup_ui(self):
        self.main_frame = ctk.CTkFrame(self.window)
        self.main_frame.pack(padx=20, pady=20, fill="both", expand=True)

        # Frame supérieure pour l'horloge et la recherche
        self.top_frame = ctk.CTkFrame(self.main_frame)
        self.top_frame.pack(pady=5, fill="x")

        # Horloge
        self.clock_label = ctk.CTkLabel(self.top_frame, text="", font=("Arial", 20))
        self.clock_label.pack(side="left", padx=10)

        # Entrée ville
        self.city_frame = ctk.CTkFrame(self.top_frame)
        self.city_frame.pack(side="right", padx=10)
        
        self.city_label = ctk.CTkLabel(self.city_frame, text="Ville:")
        self.city_label.pack(side="left", padx=5)
        
        self.city_entry = ctk.CTkEntry(self.city_frame, width=200)
        self.city_entry.pack(side="left", padx=5)
        self.city_entry.insert(0, "Paris")

        self.search_button = ctk.CTkButton(
            self.city_frame, 
            text="Obtenir la météo",
            command=self.get_weather
        )
        self.search_button.pack(side="left", padx=5)

        # Frame pour les informations météo actuelles
        self.current_weather_frame = ctk.CTkFrame(self.main_frame)
        self.current_weather_frame.pack(pady=10, fill="x")

        # Ajout d'un label pour l'icône météo
        self.weather_icon_label = ctk.CTkLabel(self.current_weather_frame, text="", font=("Arial", 40))
        self.weather_icon_label.pack(side="left", padx=20)

        self.weather_info_frame = ctk.CTkFrame(self.current_weather_frame)
        self.weather_info_frame.pack(side="left", padx=20)

        self.temp_label = ctk.CTkLabel(self.weather_info_frame, text="")
        self.temp_label.pack(pady=2)
        
        self.humidity_label = ctk.CTkLabel(self.weather_info_frame, text="")
        self.humidity_label.pack(pady=2)

        self.wind_label = ctk.CTkLabel(self.weather_info_frame, text="")
        self.wind_label.pack(pady=2)

        self.weather_label = ctk.CTkLabel(self.weather_info_frame, text="")
        self.weather_label.pack(pady=2)

        # Frame pour les graphiques
        self.graphs_frame = ctk.CTkFrame(self.main_frame)
        self.graphs_frame.pack(pady=5, fill="both", expand=True)

        # Boutons
        self.button_frame = ctk.CTkFrame(self.main_frame)
        self.button_frame.pack(pady=5, fill="x")

        self.save_button = ctk.CTkButton(
            self.button_frame,
            text="Sauvegarder",
            command=self.save_data
        )
        self.save_button.pack(side="left", padx=5)

        self.load_button = ctk.CTkButton(
            self.button_frame,
            text="Charger",
            command=self.load_data
        )
        self.load_button.pack(side="right", padx=5)

    def update_clock(self):
        current_time = datetime.now().strftime("%H:%M:%S")
        self.clock_label.configure(text=current_time)
        self.window.after(1000, self.update_clock)

    def get_weather(self):
        city = self.city_entry.get()
        
        geocoding_url = f"https://geocoding-api.open-meteo.com/v1/search?name={city}&count=1&language=fr&format=json"
        
        try:
            geo_response = requests.get(geocoding_url)
            geo_data = geo_response.json()
            
            if not geo_data.get("results"):
                messagebox.showerror("Erreur", "Ville non trouvée")
                return

            lat = geo_data["results"][0]["latitude"]
            lon = geo_data["results"][0]["longitude"]

            weather_url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&current=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code&daily=temperature_2m_max,temperature_2m_min,wind_speed_10m_max,relative_humidity_2m_max,weather_code&timezone=auto&past_days=7&forecast_days=7"
            
            weather_response = requests.get(weather_url)
            self.weather_data = weather_response.json()
            
            self.update_weather_display()
            self.update_graphs()

        except Exception as e:
            messagebox.showerror("Erreur", f"Erreur lors de la récupération des données: {str(e)}")

    def update_weather_display(self):
        current = self.weather_data["current"]
        weather_code = current['weather_code']
        weather_description, icon_key = self.weather_codes.get(weather_code, ("Condition inconnue", "cloudy"))
        
        # Mise à jour de l'icône
        self.weather_icon_label.configure(text=self.weather_icons[icon_key])
        
        self.temp_label.configure(
            text=f"Température actuelle: {current['temperature_2m']}°C"
        )
        self.humidity_label.configure(
            text=f"Humidité: {current['relative_humidity_2m']}%"
        )
        self.wind_label.configure(
            text=f"Vitesse du vent: {current['wind_speed_10m']} km/h"
        )
        self.weather_label.configure(
            text=f"Conditions: {weather_description}"
        )

    def update_graphs(self):
        for widget in self.graphs_frame.winfo_children():
            widget.destroy()

        # Créer deux sous-frames pour les graphiques
        past_frame = ctk.CTkFrame(self.graphs_frame)
        past_frame.pack(side="left", fill="both", expand=True)
        
        future_frame = ctk.CTkFrame(self.graphs_frame)
        future_frame.pack(side="right", fill="both", expand=True)

        # Graphique pour les 7 jours précédents
        fig_past = Figure(figsize=(6, 4))
        daily_data = self.weather_data["daily"]
        dates = [datetime.strptime(d, "%Y-%m-%d").strftime("%d/%m") for d in daily_data["time"][:7]]
        
        ax1 = fig_past.add_subplot(111)
        
        # Température
        temp_max = daily_data["temperature_2m_max"][:7]
        temp_min = daily_data["temperature_2m_min"][:7]
        humidity = daily_data["relative_humidity_2m_max"][:7]
        wind = daily_data["wind_speed_10m_max"][:7]
        
        ax1.plot(dates, temp_max, 'r-', label='Temp Max (°C)', marker='o')
        ax1.plot(dates, temp_min, 'b-', label='Temp Min (°C)', marker='o')
        ax1.plot(dates, humidity, 'g-', label='Humidité (%)', marker='s')
        ax1.plot(dates, wind, 'y-', label='Vent (km/h)', marker='^')
        
        ax1.set_title("7 jours précédents")
        ax1.legend(loc='upper left', bbox_to_anchor=(0, 1.15))
        ax1.grid(True, linestyle='--', alpha=0.7)
        ax1.tick_params(axis='x', rotation=45)
        
        fig_past.tight_layout()
        
        # Graphique pour les 7 jours suivants
        fig_future = Figure(figsize=(6, 4))
        dates_future = [datetime.strptime(d, "%Y-%m-%d").strftime("%d/%m") for d in daily_data["time"][7:]]
        
        ax2 = fig_future.add_subplot(111)
        
        temp_max_future = daily_data["temperature_2m_max"][7:]
        temp_min_future = daily_data["temperature_2m_min"][7:]
        humidity_future = daily_data["relative_humidity_2m_max"][7:]
        wind_future = daily_data["wind_speed_10m_max"][7:]
        
        ax2.plot(dates_future, temp_max_future, 'r-', label='Temp Max (°C)', marker='o')
        ax2.plot(dates_future, temp_min_future, 'b-', label='Temp Min (°C)', marker='o')
        ax2.plot(dates_future, humidity_future, 'g-', label='Humidité (%)', marker='s')
        ax2.plot(dates_future, wind_future, 'y-', label='Vent (km/h)', marker='^')
        
        ax2.set_title("7 prochains jours")
        ax2.legend(loc='upper left', bbox_to_anchor=(0, 1.15))
        ax2.grid(True, linestyle='--', alpha=0.7)
        ax2.tick_params(axis='x', rotation=45)
        
        fig_future.tight_layout()

        # Afficher les graphiques
        canvas_past = FigureCanvasTkAgg(fig_past, master=past_frame)
        canvas_past.draw()
        canvas_past.get_tk_widget().pack(fill="both", expand=True)

        canvas_future = FigureCanvasTkAgg(fig_future, master=future_frame)
        canvas_future.draw()
        canvas_future.get_tk_widget().pack(fill="both", expand=True)

    def save_data(self):
        try:
            # Ouvre une boîte de dialogue pour choisir l'emplacement et le nom du fichier
            filename = filedialog.asksaveasfilename(
                defaultextension=".json",
                filetypes=[("JSON files", ".json"), ("All files", ".*")],
                title="Sauvegarder les données météo"
            )
            
            if filename:  # Si un fichier a été sélectionné
                with open(filename, "w", encoding='utf-8') as f:
                    json.dump(self.weather_data, f, ensure_ascii=False)
                messagebox.showinfo("Succès", "Données sauvegardées avec succès")
        except Exception as e:
            messagebox.showerror("Erreur", f"Erreur lors de la sauvegarde: {str(e)}")

    def load_data(self):
        try:
            # Ouvre une boîte de dialogue pour choisir le fichier à charger
            filename = filedialog.askopenfilename(
                filetypes=[("JSON files", ".json"), ("All files", ".*")],
                title="Charger les données météo"
            )
            
            if filename:  # Si un fichier a été sélectionné
                with open(filename, "r", encoding='utf-8') as f:
                    self.weather_data = json.load(f)
                self.update_weather_display()
                self.update_graphs()
                messagebox.showinfo("Succès", "Données chargées avec succès")
        except Exception as e:
            messagebox.showerror("Erreur", f"Erreur lors du chargement: {str(e)}")

    def run(self):
        self.window.mainloop()

if _name_ == "_main_":
    app = WeatherApp()
    app.run()