import pandas as pd
import numpy as np
import xgboost as xgb
import mysql.connector
from mysql.connector import Error
from datetime import datetime, timedelta
import holidays

# --- NIEUW: Imports voor grafiek en e-mail ---
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

# --- NIEUW: Zorgt dat matplotlib werkt zonder GUI (bv. in terminal) ---
plt.switch_backend('Agg')

# --- CONFIGURATIE ---
MODEL_FILE = 'price_forecast_model_v1_5.json' 
TARGET = 'gemiddelde_prijs'
AANTAL_UUR_VOORSPELLEN = 72
GRAFIEK_BESTAND = 'prijs_voorspelling_windows.png' # Tijdelijk bestand

# --- NIEUW: E-mail Configuratie ---
# VUL DIT IN MET JE EIGEN GEGEVENS
EMAIL_CONFIG = {
    'smtp_server': '192.168.178.201', # Bv. 'smtp.gmail.com'
    'smtp_port': 587,
    'sender': 'sftpuser@markkors.nl',
    'password': 'Aae8-G9yFU5j',  # Voeg hier het wachtwoord toe als dat nodig is
    'receiver': 'mark@markkors.nl'
}

DB_CONFIG = {
    'host': '192.168.178.201',
    'user': 'energy_prices_user',
    'password': 'kS9R*xp17ZwCD@CV&E^N',
    'database': 'energy_prices',
    'port': 3307
}

# --- Model laden ---
try:
    print(f"Laden van model: {MODEL_FILE}...")
    model = xgb.XGBRegressor()
    model.load_model(MODEL_FILE)
    FEATURES = model.feature_names_in_
    print(f"✅ Model succesvol geladen (verwacht {len(FEATURES)} features).")
except FileNotFoundError:
    print(f"❌ Fout: Model bestand '{MODEL_FILE}' niet gevonden.")
    print("   Heb je het 'v1_5' model al getraind en opgeslagen op Windows?")
    exit()
except Exception as e:
    print(f"❌ Fout bij laden model: {e}")
    exit()

nl_holidays = holidays.Netherlands(years=[datetime.now().year, datetime.now().year + 1])


# --- Functie: haal_data_uit_database (onveranderd) ---
def haal_data_uit_database(conn):
    print("💾 Data ophalen uit MySQL...")
    
    query_hist = """
    SELECT
        w.datum_tijd, w.temperatuur, w.gevoelstemperatuur, w.neerslag,
        w.wind_richting, w.wind_snelheid, w.bewolking, w.luchtdruk, w.luchtvochtigheid,
        p_avg.gemiddelde_prijs
    FROM
        amersfoort_weer_uurlijks AS w
    LEFT JOIN 
        (SELECT datetime, AVG(price) AS gemiddelde_prijs
         FROM dynamic_price_data GROUP BY datetime) AS p_avg 
         ON w.datum_tijd = p_avg.datetime
    WHERE
        w.datum_tijd BETWEEN (UTC_TIMESTAMP() - INTERVAL 30 HOUR) AND UTC_TIMESTAMP()
    ORDER BY
        w.datum_tijd;
    """
    
    query_toekomst = f"""
    SELECT
        datum_tijd, temperatuur, gevoelstemperatuur, neerslag,
        wind_richting, wind_snelheid, bewolking, luchtdruk, luchtvochtigheid,
        NULL AS gemiddelde_prijs
    FROM
        amersfoort_weer_uurlijks
    WHERE
        datum_tijd BETWEEN UTC_TIMESTAMP() AND (UTC_TIMESTAMP() + INTERVAL {AANTAL_UUR_VOORSPELLEN} HOUR)
    ORDER BY
        datum_tijd;
    """
    
    try:
        hist_df = pd.read_sql(query_hist, conn, index_col='datum_tijd', parse_dates=['datum_tijd'])
        toekomst_df = pd.read_sql(query_toekomst, conn, index_col='datum_tijd', parse_dates=['datum_tijd'])
        
        print(f"✅ {len(hist_df)} uur historie geladen.")
        print(f"✅ {len(toekomst_df)} uur toekomstig weer geladen.")
        
        hist_df['gemiddelde_prijs'] = hist_df['gemiddelde_prijs'].ffill()
        hist_df['gemiddelde_prijs'] = hist_df['gemiddelde_prijs'].bfill()

        combined_df = pd.concat([hist_df, toekomst_df])
        
        return combined_df.sort_index()

    except Exception as e:
        print(f"❌ Fout bij ophalen data: {e}")
        return None

# --- Functie: maak_features_voor_uur (onveranderd) ---
def maak_features_voor_uur(df, timestamp):
    features = {}
    data_nu = df.loc[timestamp]
    
    features['maand'] = timestamp.month
    features['dag_van_het_jaar'] = timestamp.dayofyear
    features['is_feestdag'] = 1 if timestamp in nl_holidays else 0
    
    weer_cols = ['temperatuur', 'gevoelstemperatuur', 'neerslag', 'wind_richting', 
                 'wind_snelheid', 'bewolking', 'luchtdruk', 'luchtvochtigheid']
    for col in weer_cols:
        features[col] = data_nu[col]

    features['prijs_1u_geleden'] = df.loc[timestamp - timedelta(hours=1)]['gemiddelde_prijs']
    features['prijs_24u_geleden'] = df.loc[timestamp - timedelta(hours=24)]['gemiddelde_prijs']
    
    features['temp_avg_3u'] = df.loc[timestamp - timedelta(hours=2) : timestamp]['temperatuur'].mean()
    features['prijs_avg_6u'] = df.loc[timestamp - timedelta(hours=5) : timestamp]['gemiddelde_prijs'].mean()
    
    for dag in range(7):
        features[f'dag_{dag}'] = 1 if timestamp.dayofweek == dag else 0
    
    for uur in range(24):
        features[f'uur_{uur}'] = 1 if timestamp.hour == uur else 0

    return pd.DataFrame([features], columns=FEATURES)

# --- NIEUW: Functie om de e-mail te bouwen en te versturen ---
def send_email_with_graph(image_path, result_df):
    print("\n📬 E-mail opstellen...")
    
    msg = MIMEMultipart()
    msg['Subject'] = f"Energie Prijsvoorspelling [energy_prediction] {datetime.now().strftime('%d-%m-%Y')}"
    msg['From'] = EMAIL_CONFIG['sender']
    msg['To'] = EMAIL_CONFIG['receiver']

    laagste_prijs = result_df['Voorspelde_Prijs'].min()
    hoogste_prijs = result_df['Voorspelde_Prijs'].max()
    laagste_moment = result_df['Voorspelde_Prijs'].idxmin()
    hoogste_moment = result_df['Voorspelde_Prijs'].idxmax()
    
    body = f"""
Prijsvoorspelling voor de komende {len(result_df)} uur.
    
Laagste prijs: {laagste_prijs:.4f} (op {laagste_moment})
Hoogste prijs: {hoogste_prijs:.4f} (op {hoogste_moment})

Volledige voorspelling:
{result_df.to_string()}
"""
    msg.attach(MIMEText(body, 'plain'))

    try:
        with open(image_path, 'rb') as f:
            img_attach = MIMEImage(f.read(), name='voorspelling.png')
            msg.attach(img_attach)
        print("✅ Grafiek bijgevoegd.")
    except Exception as e:
        print(f"❌ Kon grafiek-bestand niet lezen: {e}")
        return

    try:
        print(f"Verbinding maken met SMTP server: {EMAIL_CONFIG['smtp_server']}...")
        server = smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port'])
        server.starttls()
        server.login(EMAIL_CONFIG['sender'], EMAIL_CONFIG['password'])
        
        print("Inloggen succesvol. E-mail verzenden...")
        server.sendmail(EMAIL_CONFIG['sender'], EMAIL_CONFIG['receiver'], msg.as_string())
        server.quit()
        print("✅ E-mail succesvol verzonden.")
    except Exception as e:
        print(f"❌ Fout bij verzenden e-mail: {e}")
        print("   Controleer je EMAIL_CONFIG (server, poort, e-mail en App-wachtwoord)")

# --- START VAN HET SCRIPT (Aangepast) ---
try:
    conn = mysql.connector.connect(**DB_CONFIG)
    werk_df = haal_data_uit_database(conn)
    
    if werk_df is not None:
        te_voorspellen_tijden = werk_df[werk_df['gemiddelde_prijs'].isnull()].index
        
        if len(te_voorspellen_tijden) == 0:
            print("\nDatabase is al up-to-date. Geen voorspelling nodig.")
        else:
            print(f"\n🧠 Start iteratieve voorspelling voor {len(te_voorspellen_tijden)} uur...")
            voorspellingen = []
            
            for timestamp in te_voorspellen_tijden:
                features_nu = maak_features_voor_uur(werk_df, timestamp)
                voorspelde_prijs = model.predict(features_nu)[0]
                werk_df.loc[timestamp, 'gemiddelde_prijs'] = voorspelde_prijs
                voorspellingen.append(voorspelde_prijs)
                
            print("\n" + "="*70)
            pd.set_option('display.max_rows', None) 
            print(f"--- VOORSPELDE PRIJZEN (komende {len(te_voorspellen_tijden)} uur) ---")
            
            resultaat_df = pd.DataFrame({
                'Voorspelde_Prijs': voorspellingen
            }, index=te_voorspellen_tijden)
            
            print(resultaat_df)
            print("="*70)
            
            # Grafiek maken (met 2 Y-assen en NL opmaak) en e-mailen ---
            print("\n📊 Grafiek genereren (met temperatuur en wind)...")
            try:
                # Maak de basis-figuur en de EERSTE Y-as (ax1) voor de prijs
                fig, ax1 = plt.subplots(figsize=(15, 8))
                
                # Plot de Prijs op de linker-as (ax1)
                ax1.plot(
                    resultaat_df.index, 
                    resultaat_df['Voorspelde_Prijs'], 
                    color='blue', 
                    marker='.',
                    linestyle='-',
                    label='Voorspelde Prijs'
                )
                ax1.set_ylabel('Voorspelde Prijs (€)', color='blue')
                ax1.tick_params(axis='y', labelcolor='blue')
                ax1.set_xlabel('Datum en Tijd')
                ax1.grid(True, which='major', axis='x')

                # Maak de TWEEDE Y-as (ax2) die de X-as deelt
                ax2 = ax1.twinx()
                
                weer_toekomst = werk_df.loc[te_voorspellen_tijden]
                
                # Plot Temperatuur op de rechter-as (ax2)
                ax2.plot(
                    weer_toekomst.index, 
                    weer_toekomst['temperatuur'], 
                    color='red', 
                    marker='.',
                    linestyle='--',
                    label='Temperatuur (°C)'
                )
                # Plot Windsnelheid op de rechter-as (ax2)
                ax2.plot(
                    weer_toekomst.index, 
                    weer_toekomst['wind_snelheid'], 
                    color='green', 
                    marker='x',
                    linestyle=':',
                    label='Windsnelheid (km/u)'
                )
                ax2.set_ylabel('Temperatuur / Windsnelheid', color='black')
                ax2.tick_params(axis='y', labelcolor='black')

                # Titel en gecombineerde legenda
                plt.title(f'Energieprijs & Weer Voorspelling ({len(resultaat_df)} uur)', fontsize=16)
                lines1, labels1 = ax1.get_legend_handles_labels()
                lines2, labels2 = ax2.get_legend_handles_labels()
                ax2.legend(lines1 + lines2, labels1 + labels2, loc='upper left')

                # --- NIEUW: X-as opmaken (Nederlands formaat) ---
                # Definieer het formaat: Dag-Maand Uur:Minuut (bv: 13-11 22:00)
                date_format = mdates.DateFormatter('%d-%m %H:%M')
                
                # Pas het formaat toe op de X-as
                ax1.xaxis.set_major_formatter(date_format)
                
                # Roteer de labels voor betere leesbaarheid
                plt.setp(ax1.get_xticklabels(), rotation=30, ha='right')
                # --- EINDE NIEUWE CODE ---

                # --- AANGEPAST: Gebruik fig.tight_layout() ---
                # Zorgt dat de geroteerde labels netjes in de afbeelding passen
                fig.tight_layout() 
                
                # Sla de grafiek op
                plt.savefig(GRAFIEK_BESTAND)
                plt.close(fig) # Geheugen vrijgeven
                print(f"✅ Grafiek opgeslagen als: {GRAFIEK_BESTAND}")
                
                # Stuur de e-mail (deze functie is onveranderd)
                send_email_with_graph(GRAFIEK_BESTAND, resultaat_df)
                
            except Exception as e:
                print(f"❌ Fout bij genereren van grafiek: {e}")
            # --- EINDE BLOK ---

except Error as e:
    print(f"❌ Fout met MySQL verbinding: {e}")
except Exception as e:
    print(f"❌ Een onverwachte fout is opgetreden: {e}")
finally:
    if 'conn' in locals() and conn.is_connected():
        conn.close()
        print("\nVerbinding met MySQL gesloten.")