import imaplib
import email
from email.header import decode_header
import hashlib
import requests
import logging
import time
import os
import configparser
import io

# --- CONFIGURATION INITIALE ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# === PARAMÈTRES RÉSEAU ===
URL_API = "https://monopsolut6.fr/pharma/modules/store_sender/index.php"
HEADERS = {
    "X-API-Key": "dev-secret-key-46567",
    "Content-Type": "application/json"
}
IMAP_SERVER = "ssl0.ovh.net"
EMAIL_USER = "script@ticketeasy.tech"
EMAIL_PASS = "Ticketsolut54"

# --- 1. FONCTIONS API ---

def get_allowed_data():
    try:
        response = requests.post(URL_API, json={"action": "list_senders"}, headers=HEADERS, timeout=10, verify=False)
        response.raise_for_status()
        return response.json().get('data', [])
    except Exception as e:
        logging.error(f"Erreur API (list_senders) : {e}")
        return None

def update_sender_in_db(csv_path, mail_en_clair):
    try:
        payload = {"action": "update_sender", "csv_path": csv_path, "mail": mail_en_clair}
        response = requests.post(URL_API, json=payload, headers=HEADERS, timeout=10, verify=False)
        return response.json()
    except Exception as e:
        logging.error(f"Erreur API (update_sender) : {e}")
        return None

def upload_to_stock_api(mem_file):
    url_import = "https://monopsolut6.fr/update_csv/import_stock.php"
    api_key = config_data.get('validApiKey') 
    headers = {"X-API-Key": api_key}
    try:
        # Pas de "with open", on utilise directement l'objet mem_file
        files = {'file': (mem_file.name, mem_file, 'application/octet-stream')}
        response = requests.post(url_import, files=files, headers=headers, verify=False, timeout=20)
        
        if response.status_code == 200:
            logging.info(f"🚀 API Import : Succès ! {mem_file.name} envoyé depuis la mémoire.")
            return True
        else:
            logging.error(f"❌ API Import : Échec ({response.status_code})")
            return False
    except Exception as e:
        logging.error(f"❌ Erreur Upload : {e}")
        return False
    
# --- 2. LOGIQUE ET SAUVEGARDE ---

def process_incoming_email(email_sender, subject_or_body, csv_filename_received):
    mail_hash = hashlib.sha256(email_sender.strip().lower().encode()).hexdigest()
    print(mail_hash)
    allowed_list = get_allowed_data()
    
    if not allowed_list: 
        return "RETRY_API_ERROR"

    # Nettoyage des noms pour comparaison (sans extension et en minuscule)
    def clean(fname): 
        return os.path.splitext(fname)[0].lower() if fname else ""
    
    received_file_clean = clean(csv_filename_received)

    results = []
    


    # --- ÉTAPE 1 : IF MAIL + CSV = OK (Match Parfait) ---
    # On vérifie si l'email ET le nom du fichier correspondent exactement à la BDD
    #match = next((x for x in allowed_list if x['mail'] == mail_hash and clean(x['csv_path']) == received_file_clean), None)
    for x in allowed_list:
        if x['mail'] == mail_hash and clean(x['csv_path']) == received_file_clean:
            if x not in results:
                logging.info(f"🎯 Match Parfait trouvé : {x['name']}")
                results.append(x) # On l'ajoute à la liste sans s'arrêter

    # --- ÉTAPE 2 : ELSE IF CSV = OK (Nom du fichier contient le nom de la borne ou correspond exactement au csv_path) ---
    # On cherche si le 'name' de la borne (ex: Buc) est écrit dans le nom du fichier reçu  ou si le nom du fichier est exactement stockticketeasybuc
    if not results:
        for item in allowed_list:
            official_csv = clean(item['csv_path'])
            #kiosk_name = item['name'].lower()
            if official_csv and official_csv == received_file_clean:
                if item not in results:
                    logging.info(f"📂 Match par Fichier : {item['name']}")
                    results.append(item)

    # --- ÉTAPE 3 : ELSE IF MAIL = OK (Email déjà connu en BDD) ---
    # On vérifie si cet expéditeur est déjà lié à une borne
    #match = next((x for x in allowed_list if x['mail'] == mail_hash), None)
    if not results:
        for item in allowed_list:
            if item.get('mail') == mail_hash:
                 if item not in results:
                    logging.info(f"📧 Match par Mail : {item['name']}")
                    results.append(item)

    # --- ÉTAPE 4 : MATCH PAR TEXTE (NOM BORNE ) ---
    if not results:
        text_to_search = subject_or_body.lower()
        for item in allowed_list:
            kiosk_name = item.get('name', '').lower()
        
        # On vérifie d'abord que les chaînes ne sont pas vides AVANT le "in"
            found_name = kiosk_name and kiosk_name in text_to_search

            if found_name:
                if item not in results:
                    logging.info(f"📝 Match par Texte : Trouvé '{kiosk_name}'")
                    results.append(item)

    # --- 
    if results:
        logging.info(f"✅ {len(results)} borne(s) identifiée(s) pour ce mail.")
        return {"status": "OK", "data_list": results}

    logging.error(f"🚫 Aucun match trouvé pour {email_sender}")
    return "REJECT"

# --- 1. FONCTIONS DE TRANSMISSION ---
def send_sms_alert(message_text):
    # Remplace par ton URL réelle (ex: https://api.fournisseursms.com/send)
    url_sms = "https://www.ovh.com/cgi-bin/sms/http2sms.cgi" 
    
    phone_numbers = ["0695278966", "0749708936"] 

    for phone in phone_numbers:
        # Nettoyage : retire le 0 initial et garde les 9 chiffres restants
        phone_clean = phone.lstrip('0').replace(" ", "").replace("+33", "")
        
        payload = {
            'account': 'sms--1',
            'login': 'Philippe',
            'password': 'Phil1234', # <--- Ne pas oublier !
            'from': 'Easy Task',
            'senderForResponse': '1',
            'to': f"0033{phone_clean}", 
            'message': message_text 
        }

        try:
            # Note : On utilise 'data' car c'est un formulaire standard (POST), 
            # mais vérifie si ton API préfère 'json=payload'
            response = requests.post(url_sms, data=payload, timeout=10, verify=False)
            
            if response.status_code == 200:
                logging.info(f"📱 SMS envoyé au 0033{phone_clean}")
            else:
                logging.error(f"❌ Erreur SMS {response.status_code}: {response.text}")
        except Exception as e:
            logging.error(f"❌ Erreur réseau SMS : {e}")


def renamed_file(msg, official_name):
    for part in msg.walk():
        filename = part.get_filename()
        if filename and (filename.lower().endswith('.csv') or filename.lower().endswith('.xlsx')):
            ext = os.path.splitext(filename)[1] 
            official_base = os.path.splitext(official_name)[0]
            final_name = official_base + ext 
            
            # On récupère les données et on les met dans un stream en mémoire
            file_data = part.get_payload(decode=True)
            mem_file = io.BytesIO(file_data)
            mem_file.name = final_name  # Important pour que requests connaisse le nom
            
            return mem_file
    return None



# --- 3. LE CAPTEUR (IMAP) ---

def listen_to_mailbox():
    try:
        mail = imaplib.IMAP4_SSL(IMAP_SERVER)
        mail.login(EMAIL_USER, EMAIL_PASS)
        mail.select("inbox")
        status, messages = mail.search(None, 'UNSEEN')
        
        for num in messages[0].split():
            res, msg_data = mail.fetch(num, '(RFC822)')
            for response_part in msg_data:
                if isinstance(response_part, tuple):
                    msg = email.message_from_bytes(response_part[1])
                    email_sender = email.utils.parseaddr(msg['From'])[1]
                    subject = decode_header(msg['Subject'])[0][0]
                    if isinstance(subject, bytes): subject = subject.decode()
                    
                    csv_filename_received = None
                    body_content = ""

                    for part in msg.walk():
                        # MODIFICATION 2 : Détecter .csv ou .xlsx ici aussi
                        fname = part.get_filename()
                        if fname and (fname.lower().endswith('.csv') or fname.lower().endswith('.xlsx')):
                            csv_filename_received = fname
                        if part.get_content_type() == "text/plain":
                            body_content = part.get_payload(decode=True).decode(errors='ignore')

                    full_text = f"{subject} {body_content}"
                    logging.info(f"Analyse mail de : {email_sender}")
                    
                    res_decision = process_incoming_email(email_sender, full_text, csv_filename_received)
                    
                    if isinstance(res_decision, dict) and "data_list" in res_decision:
                        kiosks = res_decision['data_list']
                        
                        # On prépare le fichier une seule fois (basé sur le 1er kiosque trouvé)
                        mem_file = renamed_file(msg, kiosks[0]['csv_path'])
                        
                        if mem_file:
                            for k in kiosks:
                                logging.info(f"✅ Traitement de : {k['name']}")
                                
                                # Si c'est une nouvelle liaison ou si le mail est manquant
                                if res_decision.get('status') == "UPDATE_MAIL" or k.get('mail') is None:
                                    logging.info(f"🔗 Liaison auto : {email_sender} -> {k['csv_path']}")
                                    update_sender_in_db(k['csv_path'], email_sender)
                            
                            # Upload unique du fichier
                            upload_success = upload_to_stock_api(mem_file)
                            if upload_success:
                                logging.info(f"🚀 Terminé : {len(kiosks)} borne(s) mises à jour.")
                    else:
                        logging.warning(f"❌ Rejet pour {email_sender}")
                        send_sms_alert(f"EasyTask: Acces refuse pour {email_sender}")
        mail.logout()
    except Exception as e:
        logging.error(f"Erreur IMAP : {e}")

if __name__ == "__main__":
    logging.info(" Robot de surveillance activé...")
    
    # On définit l'intervalle de vérification (en secondes)
    # 60 secondes = 1 minute
    CHECK_INTERVAL = 60 

    while True:
        try:
            logging.info(" Vérification des nouveaux messages...")
            listen_to_mailbox()
            
        except Exception as e:
            # En cas d'erreur (perte de connexion internet, etc.), 
            # le script ne s'arrête pas, il log l'erreur et réessaiera.
            logging.error(f"⚠️ Une erreur est survenue dans la boucle : {e}")
        
        # Pause avant la prochaine vérification pour ne pas saturer le serveur IMAP
        time.sleep(CHECK_INTERVAL)