import de.vertico.starface.module.core.model.VariableType;
import de.vertico.starface.module.core.model.Visibility;
import de.vertico.starface.module.core.runtime.IBaseExecutable;
import de.vertico.starface.module.core.runtime.IRuntimeEnvironment;
import de.vertico.starface.module.core.runtime.annotations.Function;
import de.vertico.starface.module.core.runtime.annotations.InputVar;
import de.vertico.starface.module.core.runtime.annotations.OutputVar;

import javax.mail.*;
import javax.mail.internet.MimeBodyPart;
import javax.mail.search.FlagTerm;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Mail2FaxBlock - STARFACE Custom Block
 *
 * Ruft E-Mails ab und sendet PDF-Anhänge als Fax.
 * Die Ziel-Faxnummer wird aus dem E-Mail-Betreff gelesen.
 *
 * Für STARFACE 8.x, 9.x, 10.x (Java 21)
 */
@Function(
    visibility = Visibility.Private,
    description = "Ruft E-Mails ab und sendet PDF-Anhänge als Fax"
)
public class Mail2FaxBlock implements IBaseExecutable {

    // Fax result constants (instead of inner class to avoid separate .class file)
    private static final int FAX_SUCCESS = 0;
    private static final int FAX_RETRY = 1;
    private static final int FAX_FAIL = 2;

    // Lock um parallele Ausführung zu verhindern
    private static final ReentrantLock executionLock = new ReentrantLock();

    // Pfade für Tracking-Dateien
    private static final String DATA_DIR = "/var/starface/module-data";
    private static final String PROCESSED_FILE = DATA_DIR + "/mail2fax_processed.txt";
    private static final String RETRY_FILE = DATA_DIR + "/mail2fax_retry.txt";

    // ============================================================
    // INPUT VARIABLEN - werden im Module Designer konfiguriert
    // ============================================================

    @InputVar(
        label = "Mail Server",
        description = "IMAP oder POP3 Server Adresse",
        type = VariableType.STRING
    )
    public String mailServer = "";

    @InputVar(
        label = "Mail Port",
        description = "Server Port (993 für IMAPS, 995 für POP3S, 143 für IMAP, 110 für POP3)",
        type = VariableType.NUMBER
    )
    public Integer mailPort = 993;

    @InputVar(
        label = "Protokoll",
        description = "IMAP oder POP3",
        type = VariableType.STRING
    )
    public String mailProtocol = "IMAP";

    @InputVar(
        label = "Benutzername",
        description = "E-Mail Benutzername",
        type = VariableType.STRING
    )
    public String mailUsername = "";

    @InputVar(
        label = "Passwort",
        description = "E-Mail Passwort",
        type = VariableType.STRING
    )
    public String mailPassword = "";

    @InputVar(
        label = "SSL verwenden",
        description = "SSL/TLS für die Verbindung aktivieren",
        type = VariableType.BOOLEAN
    )
    public Boolean mailUseSsl = true;

    @InputVar(
        label = "Ordner",
        description = "E-Mail Ordner (Standard: INBOX)",
        type = VariableType.STRING
    )
    public String mailFolder = "INBOX";

    @InputVar(
        label = "Nach Verarbeitung löschen",
        description = "E-Mails nach erfolgreicher Verarbeitung löschen (nur IMAP, bei POP3 werden E-Mails immer nach erfolgreichem Versand gelöscht)",
        type = VariableType.BOOLEAN
    )
    public Boolean deleteAfterProcess = false;

    @InputVar(
        label = "Fax-Benutzer",
        description = "STARFACE Benutzer für den Fax-Versand (muss Fax-Berechtigung haben)",
        type = VariableType.STARFACE_USER
    )
    public Integer faxAccountId = 0;

    @InputVar(
        label = "Absender-Faxnummer",
        description = "Ausgehende Faxnummer (z.B. +49721123456)",
        type = VariableType.STRING
    )
    public String faxSenderNumber = "";

    @InputVar(
        label = "Erlaubte Absender",
        description = "Komma-getrennte Liste erlaubter Absender-Adressen (leer = alle erlaubt)",
        type = VariableType.STRING
    )
    public String authorizedSenders = "";

    @InputVar(
        label = "Betreff-Präfix",
        description = "Präfix im Betreff (optional). Wenn gesetzt, muss der Betreff mit diesem Präfix beginnen (z.B. 'FAXMaik:'). Ermöglicht Filter-Regeln im E-Mail-Client für mehrere Fax-Instanzen.",
        type = VariableType.STRING
    )
    public String subjectPrefix = "";

    @InputVar(
        label = "PIN",
        description = "Sicherheits-PIN (optional). Wenn gesetzt, muss die PIN im E-Mail-Text enthalten sein um das Fax zu senden.",
        type = VariableType.STRING
    )
    public String pin = "";

    @InputVar(
        label = "Max. Wiederholungen",
        description = "Maximale Anzahl Wiederholungsversuche bei besetzter Leitung",
        type = VariableType.NUMBER
    )
    public Integer maxRetries = 3;

    @InputVar(
        label = "Wartezeit (Minuten)",
        description = "Minuten zwischen Wiederholungsversuchen",
        type = VariableType.NUMBER
    )
    public Integer retryDelayMinutes = 5;

    // ============================================================
    // OUTPUT VARIABLEN - Ergebnisse der Ausführung
    // ============================================================

    @OutputVar(
        label = "Verarbeitete E-Mails",
        description = "Anzahl der verarbeiteten E-Mails",
        type = VariableType.NUMBER
    )
    public Integer processedCount = 0;

    @OutputVar(
        label = "Gesendete Faxe",
        description = "Anzahl erfolgreich gesendeter Faxe",
        type = VariableType.NUMBER
    )
    public Integer sentFaxCount = 0;

    @OutputVar(
        label = "Fehleranzahl",
        description = "Anzahl der Fehler",
        type = VariableType.NUMBER
    )
    public Integer errorCount = 0;

    @OutputVar(
        label = "Wartende Wiederholungen",
        description = "Anzahl der Faxe die auf Wiederholung warten",
        type = VariableType.NUMBER
    )
    public Integer pendingRetries = 0;

    @OutputVar(
        label = "Status",
        description = "Status-Meldung der letzten Ausführung",
        type = VariableType.STRING
    )
    public String statusMessage = "";

    // Runtime Environment
    private IRuntimeEnvironment runtime;
    private org.apache.logging.log4j.Logger log;

    @Override
    public void execute(IRuntimeEnvironment runtime) throws Exception {
        this.runtime = runtime;
        this.log = runtime.getLog();

        // Pflichtfelder validieren
        List<String> missingFields = new ArrayList<>();

        if (mailServer == null || mailServer.trim().isEmpty()) {
            missingFields.add("mailServer (Mail Server)");
        }
        if (mailPort == null || mailPort <= 0) {
            missingFields.add("mailPort (Port)");
        }
        if (mailUsername == null || mailUsername.trim().isEmpty()) {
            missingFields.add("mailUsername (Benutzername)");
        }
        if (mailPassword == null || mailPassword.trim().isEmpty()) {
            missingFields.add("mailPassword (Passwort)");
        }
        if (faxAccountId == null || faxAccountId <= 0) {
            missingFields.add("faxAccountId (Fax-Benutzer)");
        }
        if (faxSenderNumber == null || faxSenderNumber.trim().isEmpty()) {
            missingFields.add("faxSenderNumber (Absender-Faxnummer)");
        }

        if (!missingFields.isEmpty()) {
            statusMessage = "Konfigurationsfehler: Pflichtfelder nicht ausgefüllt";
            log.error("Mail2Fax: " + statusMessage + ": " + String.join(", ", missingFields));
            return;
        }

        // Versuche Lock zu bekommen - wenn nicht verfügbar, läuft bereits eine Instanz
        if (!executionLock.tryLock()) {
            log.info("Mail2Fax: Bereits eine Instanz aktiv, überspringe Ausführung");
            statusMessage = "Übersprungen - bereits aktiv";
            return;
        }

        try {
            log.info("Mail2Fax: Starte E-Mail-Abruf von " + mailServer);

            // Datenverzeichnis erstellen
            Files.createDirectories(Paths.get(DATA_DIR));

            // Zuerst Retry-Queue verarbeiten
            processRetryQueue();

            // Dann neue E-Mails abrufen
            fetchAndProcessEmails();

            statusMessage = String.format(
                "Fertig: %d E-Mails verarbeitet, %d Faxe gesendet, %d Fehler, %d warten auf Retry",
                processedCount, sentFaxCount, errorCount, pendingRetries
            );
            log.info("Mail2Fax: " + statusMessage);

        } finally {
            executionLock.unlock();
        }
    }

    /**
     * Verarbeitet die Retry-Queue für fehlgeschlagene Faxe
     */
    private void processRetryQueue() {
        try {
            Path retryPath = Paths.get(RETRY_FILE);
            if (!Files.exists(retryPath)) {
                return;
            }

            List<String> lines = Files.readAllLines(retryPath);
            List<String> remaining = new ArrayList<>();
            long now = System.currentTimeMillis();

            for (String line : lines) {
                if (line.trim().isEmpty()) continue;

                // Format: timestamp|retryCount|destination|senderNumber|pdfPath|messageId
                String[] parts = line.split("\\|", 6);
                if (parts.length < 6) continue;

                long scheduledTime = Long.parseLong(parts[0]);
                int retryCount = Integer.parseInt(parts[1]);
                String destination = parts[2];
                String senderNumber = parts[3];
                String pdfPath = parts[4];
                String messageId = parts[5];

                if (now < scheduledTime) {
                    // Noch nicht Zeit für Retry
                    remaining.add(line);
                    pendingRetries++;
                    continue;
                }

                // Retry durchführen
                File pdfFile = new File(pdfPath);
                if (!pdfFile.exists()) {
                    log.warn("Mail2Fax: Retry-PDF nicht mehr vorhanden: " + pdfPath);
                    continue;
                }

                log.info("Mail2Fax: Retry #" + retryCount + " für " + destination);
                int result = sendFax(destination, senderNumber, pdfFile);

                if (result == FAX_SUCCESS) {
                    sentFaxCount++;
                    pdfFile.delete(); // Temp-Datei löschen
                    markAsProcessed(messageId);
                } else if (result == FAX_RETRY && retryCount < maxRetries) {
                    // Erneut in Queue
                    long nextRetry = now + (retryDelayMinutes * 60 * 1000L);
                    remaining.add(nextRetry + "|" + (retryCount + 1) + "|" + destination + "|" +
                                  senderNumber + "|" + pdfPath + "|" + messageId);
                    pendingRetries++;
                } else {
                    log.error("Mail2Fax: Endgültig fehlgeschlagen nach " + retryCount + " Versuchen: " + destination);
                    errorCount++;
                    pdfFile.delete();
                }
            }

            // Aktualisierte Queue speichern
            Files.write(retryPath, remaining);

        } catch (Exception e) {
            log.error("Mail2Fax: Fehler bei Retry-Queue: " + e.getMessage(), e);
        }
    }

    /**
     * Ruft E-Mails ab und verarbeitet sie
     */
    private void fetchAndProcessEmails() {
        Store store = null;
        Folder folder = null;

        try {
            // Session konfigurieren
            Properties props = new Properties();
            String protocol = mailProtocol.toUpperCase();

            if (protocol.equals("IMAP")) {
                if (mailUseSsl) {
                    props.put("mail.store.protocol", "imaps");
                    props.put("mail.imaps.host", mailServer);
                    props.put("mail.imaps.port", String.valueOf(mailPort));
                    props.put("mail.imaps.ssl.enable", "true");
                } else {
                    props.put("mail.store.protocol", "imap");
                    props.put("mail.imap.host", mailServer);
                    props.put("mail.imap.port", String.valueOf(mailPort));
                }
            } else { // POP3
                if (mailUseSsl) {
                    props.put("mail.store.protocol", "pop3s");
                    props.put("mail.pop3s.host", mailServer);
                    props.put("mail.pop3s.port", String.valueOf(mailPort));
                    props.put("mail.pop3s.ssl.enable", "true");
                } else {
                    props.put("mail.store.protocol", "pop3");
                    props.put("mail.pop3.host", mailServer);
                    props.put("mail.pop3.port", String.valueOf(mailPort));
                }
            }

            Session session = Session.getInstance(props);
            store = session.getStore();
            store.connect(mailServer, mailPort, mailUsername, mailPassword);

            folder = store.getFolder(mailFolder);
            folder.open(Folder.READ_WRITE);

            // Nachrichten abrufen
            Message[] messages;
            if (protocol.equals("IMAP")) {
                // IMAP: Nur ungelesene
                messages = folder.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
            } else {
                // POP3: Alle (Tracking über processed-Liste)
                messages = folder.getMessages();
            }

            log.info("Mail2Fax: " + messages.length + " Nachrichten gefunden");

            for (Message message : messages) {
                try {
                    processMessage(message, protocol.equals("POP3"), folder);
                    processedCount++;
                } catch (Exception e) {
                    log.error("Mail2Fax: Fehler bei Nachricht: " + e.getMessage(), e);
                    errorCount++;
                }
            }

        } catch (Exception e) {
            // Bei Verbindungsfehlern nur eine saubere Meldung ohne Stacktrace
            String msg = e.getMessage();
            if (e instanceof com.sun.mail.util.MailConnectException ||
                e instanceof java.net.ConnectException ||
                e instanceof java.net.UnknownHostException ||
                e instanceof java.net.SocketTimeoutException ||
                (msg != null && (msg.contains("Connection refused") ||
                                 msg.contains("connect") ||
                                 msg.contains("timeout") ||
                                 msg.contains("Unknown host")))) {
                log.error("Mail2Fax: Verbindung zu " + mailServer + ":" + mailPort + " fehlgeschlagen - " + msg);
            } else {
                log.error("Mail2Fax: E-Mail-Abruf fehlgeschlagen: " + msg, e);
            }
            errorCount++;
            statusMessage = "Fehler: " + msg;
        } finally {
            try {
                if (folder != null && folder.isOpen()) {
                    folder.close(true); // expunge deleted messages
                }
                if (store != null) {
                    store.close();
                }
            } catch (Exception e) {
                log.warn("Mail2Fax: Fehler beim Schließen: " + e.getMessage());
            }
        }
    }

    /**
     * Verarbeitet eine einzelne E-Mail
     */
    private void processMessage(Message message, boolean isPop3, Folder folder) throws Exception {
        String messageId = getMessageId(message);

        // Bei POP3: Prüfen ob bereits verarbeitet
        if (isPop3 && isAlreadyProcessed(messageId)) {
            log.debug("Mail2Fax: Nachricht bereits verarbeitet: " + messageId);
            return;
        }

        String from = message.getFrom()[0].toString();
        String subject = message.getSubject();

        log.info("Mail2Fax: Verarbeite E-Mail von " + from + " - Betreff: " + subject);

        // Absender prüfen
        if (!isAuthorizedSender(from)) {
            log.warn("Mail2Fax: Nicht autorisierter Absender: " + from);
            if (!isPop3) {
                message.setFlag(Flags.Flag.SEEN, true);
            }
            return;
        }

        // PIN prüfen (wenn gesetzt)
        if (pin != null && !pin.trim().isEmpty()) {
            String emailBody = getEmailBodyText(message);
            if (emailBody == null || !emailBody.contains(pin)) {
                log.error("Mail2Fax: PIN in Emailtext nicht vorhanden oder falsch");
                if (!isPop3) {
                    message.setFlag(Flags.Flag.SEEN, true);
                }
                return;
            }
            log.debug("Mail2Fax: PIN erfolgreich validiert");
        }

        // Ziel-Faxnummer aus Betreff extrahieren
        String destination = extractFaxNumber(subject);
        if (destination == null || destination.isEmpty()) {
            // Spezifische Fehlermeldung je nach Grund
            if (subjectPrefix != null && !subjectPrefix.trim().isEmpty() && !subject.startsWith(subjectPrefix.trim())) {
                log.warn("Mail2Fax: Betreff-Präfix stimmt nicht überein. Erwartet: '" + subjectPrefix.trim() + "', Betreff: " + subject);
            } else {
                log.warn("Mail2Fax: Keine gültige Faxnummer im Betreff: " + subject);
            }
            if (!isPop3) {
                message.setFlag(Flags.Flag.SEEN, true);
            }
            return;
        }

        // PDF-Anhänge suchen und verarbeiten
        List<File> pdfFiles = extractPdfAttachments(message);
        if (pdfFiles.isEmpty()) {
            log.warn("Mail2Fax: Keine PDF-Anhänge gefunden");
            if (!isPop3) {
                message.setFlag(Flags.Flag.SEEN, true);
            }
            return;
        }

        // Jeden PDF-Anhang als Fax senden
        boolean allSuccess = true;
        for (File pdfFile : pdfFiles) {
            int result = sendFax(destination, faxSenderNumber, pdfFile);

            if (result == FAX_SUCCESS) {
                sentFaxCount++;
                pdfFile.delete();
            } else if (result == FAX_RETRY) {
                // In Retry-Queue aufnehmen
                addToRetryQueue(destination, faxSenderNumber, pdfFile, messageId);
                allSuccess = false;
            } else {
                errorCount++;
                pdfFile.delete();
                allSuccess = false;
            }
        }

        // E-Mail als verarbeitet markieren
        if (allSuccess) {
            if (isPop3) {
                // POP3: Als verarbeitet speichern und löschen
                markAsProcessed(messageId);
                message.setFlag(Flags.Flag.DELETED, true);
                log.info("Mail2Fax: POP3-Nachricht zum Löschen markiert");
            } else {
                // IMAP: Als gelesen markieren, optional löschen
                message.setFlag(Flags.Flag.SEEN, true);
                if (deleteAfterProcess) {
                    message.setFlag(Flags.Flag.DELETED, true);
                }
            }
        }
    }

    /**
     * Ermittelt die Message-ID einer E-Mail
     */
    private String getMessageId(Message message) {
        try {
            String[] headers = message.getHeader("Message-ID");
            if (headers != null && headers.length > 0) {
                return headers[0];
            }
            // Fallback: Hash aus Datum und Betreff
            return String.valueOf((message.getSentDate() + "|" + message.getSubject()).hashCode());
        } catch (Exception e) {
            return String.valueOf(System.currentTimeMillis());
        }
    }

    /**
     * Prüft ob eine Nachricht bereits verarbeitet wurde (für POP3)
     */
    private boolean isAlreadyProcessed(String messageId) {
        try {
            Path path = Paths.get(PROCESSED_FILE);
            if (!Files.exists(path)) {
                return false;
            }
            List<String> processed = Files.readAllLines(path);
            return processed.contains(messageId);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Markiert eine Nachricht als verarbeitet (für POP3)
     */
    private void markAsProcessed(String messageId) {
        try {
            Path path = Paths.get(PROCESSED_FILE);
            List<String> processed = Files.exists(path) ?
                new ArrayList<>(Files.readAllLines(path)) : new ArrayList<>();

            if (!processed.contains(messageId)) {
                processed.add(messageId);
                // Maximal 1000 Einträge behalten
                while (processed.size() > 1000) {
                    processed.remove(0);
                }
                Files.write(path, processed);
            }
        } catch (Exception e) {
            log.warn("Mail2Fax: Konnte Nachricht nicht als verarbeitet markieren: " + e.getMessage());
        }
    }

    /**
     * Fügt ein fehlgeschlagenes Fax zur Retry-Queue hinzu
     */
    private void addToRetryQueue(String destination, String senderNumber, File pdfFile, String messageId) {
        try {
            long nextRetry = System.currentTimeMillis() + (retryDelayMinutes * 60 * 1000L);
            String entry = nextRetry + "|1|" + destination + "|" + senderNumber + "|" +
                          pdfFile.getAbsolutePath() + "|" + messageId;

            Path path = Paths.get(RETRY_FILE);
            List<String> entries = Files.exists(path) ?
                new ArrayList<>(Files.readAllLines(path)) : new ArrayList<>();
            entries.add(entry);
            Files.write(path, entries);

            pendingRetries++;
            log.info("Mail2Fax: Fax zur Retry-Queue hinzugefügt: " + destination);

        } catch (Exception e) {
            log.error("Mail2Fax: Konnte nicht zur Retry-Queue hinzufügen: " + e.getMessage());
        }
    }

    /**
     * Prüft ob der Absender autorisiert ist
     */
    private boolean isAuthorizedSender(String from) {
        if (authorizedSenders == null || authorizedSenders.trim().isEmpty()) {
            return true; // Keine Einschränkung
        }

        String fromLower = from.toLowerCase();
        String[] authorized = authorizedSenders.split(",");

        for (String auth : authorized) {
            if (fromLower.contains(auth.trim().toLowerCase())) {
                return true;
            }
        }

        return false;
    }

    /**
     * Extrahiert die Faxnummer aus dem E-Mail-Betreff
     *
     * Wenn ein Betreff-Präfix konfiguriert ist, muss der Betreff damit beginnen.
     * Der Präfix wird dann entfernt, bevor die Faxnummer extrahiert wird.
     *
     * Beispiel: subjectPrefix="FAXMaik:", subject="FAXMaik: +49721123456" → "+49721123456"
     */
    private String extractFaxNumber(String subject) {
        if (subject == null || subject.isEmpty()) {
            return null;
        }

        // Wenn Präfix gesetzt ist, prüfen und entfernen
        if (subjectPrefix != null && !subjectPrefix.trim().isEmpty()) {
            String prefix = subjectPrefix.trim();

            if (!subject.startsWith(prefix)) {
                log.debug("Mail2Fax: Betreff beginnt nicht mit Präfix '" + prefix + "': " + subject);
                return null;
            }

            // Präfix entfernen
            subject = subject.substring(prefix.length()).trim();
            log.debug("Mail2Fax: Präfix entfernt, verbleibender Betreff: " + subject);
        }

        // Entferne alle Zeichen außer Ziffern und +
        String cleaned = subject.replaceAll("[^0-9+]", "");

        // Prüfe auf gültiges Format
        if (cleaned.matches("\\+?[0-9]{6,}")) {
            return cleaned;
        }

        return null;
    }

    /**
     * Extrahiert den Textinhalt einer E-Mail (für PIN-Prüfung)
     */
    private String getEmailBodyText(Message message) {
        try {
            Object content = message.getContent();

            if (content instanceof String) {
                return (String) content;
            } else if (content instanceof Multipart) {
                Multipart multipart = (Multipart) content;
                StringBuilder bodyText = new StringBuilder();

                for (int i = 0; i < multipart.getCount(); i++) {
                    BodyPart bodyPart = multipart.getBodyPart(i);
                    String contentType = bodyPart.getContentType().toLowerCase();

                    // Nur Text-Parts auslesen, keine Anhänge
                    if (contentType.startsWith("text/plain") || contentType.startsWith("text/html")) {
                        Object partContent = bodyPart.getContent();
                        if (partContent instanceof String) {
                            bodyText.append((String) partContent);
                        }
                    }
                }
                return bodyText.toString();
            }
        } catch (Exception e) {
            log.warn("Mail2Fax: Fehler beim Lesen des E-Mail-Textes: " + e.getMessage());
        }
        return null;
    }

    /**
     * Extrahiert PDF-Anhänge aus der E-Mail
     */
    private List<File> extractPdfAttachments(Message message) throws Exception {
        List<File> pdfFiles = new ArrayList<>();

        Object content = message.getContent();
        if (content instanceof Multipart) {
            Multipart multipart = (Multipart) content;

            for (int i = 0; i < multipart.getCount(); i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);

                if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()) ||
                    (bodyPart.getFileName() != null && bodyPart.getFileName().toLowerCase().endsWith(".pdf"))) {

                    String fileName = bodyPart.getFileName();
                    if (fileName != null && fileName.toLowerCase().endsWith(".pdf")) {
                        // Temp-Datei erstellen
                        File tempFile = File.createTempFile("mail2fax_", ".pdf");

                        try (InputStream is = bodyPart.getInputStream();
                             FileOutputStream fos = new FileOutputStream(tempFile)) {
                            byte[] buffer = new byte[4096];
                            int bytesRead;
                            while ((bytesRead = is.read(buffer)) != -1) {
                                fos.write(buffer, 0, bytesRead);
                            }
                        }

                        log.info("Mail2Fax: PDF extrahiert: " + fileName);
                        pdfFiles.add(tempFile);
                    }
                }
            }
        }

        return pdfFiles;
    }

    /**
     * Sendet ein PDF als Fax über die STARFACE API
     *
     * Verwendet den internen FaxHandler über den StarfaceComponentProvider.
     *
     * @return FAX_SUCCESS, FAX_RETRY oder FAX_FAIL
     */
    private int sendFax(String destination, String callingNumber, File pdfFile) {
        try {
            log.info("Mail2Fax: Sende Fax an " + destination + " von " + callingNumber);

            // Den eingebauten SendFax-Block direkt instanziieren und aufrufen
            Class<?> sendFaxClass = Class.forName(
                "de.vertico.starface.module.core.runtime.functions.callHandling.call.SendFax"
            );

            Object sendFaxBlock = sendFaxClass.getDeclaredConstructor().newInstance();

            // Input-Variablen setzen via Reflection
            // accountId (Integer) - Benutzer-ID für Fax-Versand
            setFieldValue(sendFaxClass, sendFaxBlock, "accountId", faxAccountId);

            // extention (String) - Ziel-Faxnummer (Tippfehler im Original!)
            setFieldValue(sendFaxClass, sendFaxBlock, "extention", destination);

            // signalNumber (String) - Absender-Nummer
            setFieldValue(sendFaxClass, sendFaxBlock, "signalNumber", callingNumber);

            // signalName (String) - Absender-Name (optional, gleich wie Nummer)
            setFieldValue(sendFaxClass, sendFaxBlock, "signalName", callingNumber);

            // resource (String) - Pfad zur PDF-Datei
            setFieldValue(sendFaxClass, sendFaxBlock, "resource", pdfFile.getAbsolutePath());

            // execute() aufrufen mit unserem Runtime
            java.lang.reflect.Method executeMethod = sendFaxClass.getMethod("execute",
                Class.forName("de.vertico.starface.module.core.runtime.IRuntimeEnvironment"));
            executeMethod.invoke(sendFaxBlock, runtime);

            // Ergebnis prüfen (exitStatus Feld)
            try {
                java.lang.reflect.Field exitStatusField = sendFaxClass.getDeclaredField("exitStatus");
                exitStatusField.setAccessible(true);
                Object exitStatus = exitStatusField.get(sendFaxBlock);
                log.info("Mail2Fax: SendFax exitStatus: " + exitStatus);

                if (exitStatus != null && exitStatus.toString().contains("FAILED")) {
                    return FAX_RETRY;
                }
            } catch (NoSuchFieldException e) {
                log.debug("Mail2Fax: Kein exitStatus Feld");
            }

            log.info("Mail2Fax: Fax erfolgreich gesendet an " + destination);
            return FAX_SUCCESS;

        } catch (Exception e) {
            String error = e.getMessage() != null ? e.getMessage().toLowerCase() : "";
            log.error("Mail2Fax: Fax-Fehler: " + e.getMessage(), e);

            // Prüfe ob Retry sinnvoll ist
            if (error.contains("busy") || error.contains("besetzt") ||
                error.contains("no answer") || error.contains("keine antwort") ||
                error.contains("temporarily") || error.contains("timeout")) {
                log.info("Mail2Fax: Temporärer Fehler, wird erneut versucht");
                return FAX_RETRY;
            }

            return FAX_FAIL;
        }
    }

    /**
     * Versucht ein Feld zu setzen, gibt true zurück wenn erfolgreich
     */
    private boolean trySetField(Class<?> clazz, Object obj, String fieldName, Object value) {
        try {
            java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
            log.debug("Mail2Fax: " + fieldName + " gesetzt: " + value);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        } catch (Exception e) {
            log.warn("Mail2Fax: Fehler beim Setzen von " + fieldName + ": " + e.getMessage());
            return false;
        }
    }

    /**
     * Setzt ein Feld oder wirft Exception
     */
    private void setFieldValue(Class<?> clazz, Object obj, String fieldName, Object value) throws Exception {
        java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
        log.debug("Mail2Fax: " + fieldName + " gesetzt: " + value);
    }
}
