package hr.com.port.ips.eracun.scheduler;

import hr.com.port.functions.Functions;
import hr.com.port.ips.eracun.boot.EracunSyncConfig;
import hr.com.port.ips.eracun.service.EracunSyncService;
import hr.com.port.connectionPool.__Pool;
import org.apache.log4j.Logger;

import java.sql.Connection;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

// Scheduler za periodičko pokretanje sinkronizacije procesnih statusa (Inbox/Outbox).
//
// Očekivani dodatci u EracunSyncConfig (ako već nemaš):
//   - boolean processInboxEnabled()
//   - boolean processOutboxEnabled()
//   - long processInboxIntervalSeconds()
//   - long processOutboxIntervalSeconds()
//   - long initialDelaySeconds()        (možeš reciklirati postojeći)
//
// Ako ne želiš dodavati nova polja u config, možeš hardkodirati periode u start(...)
// ili dodati alternativni konstruktor koji prima periode izvana.
public class ProcessStatusScheduler {

    private static final Logger logger = Logger.getLogger(ProcessStatusScheduler.class);

    private final EracunSyncConfig cfg;
    private final EracunSyncService syncService;

    private final ScheduledExecutorService exec;
    private ScheduledFuture<?> inboxFuture;
    private ScheduledFuture<?> outboxFuture;

    // Supplier za Connection koji koristi __Pool i logira greške na vaš način
    private final Supplier<Connection> connectionSupplier;

    public ProcessStatusScheduler(EracunSyncConfig cfg, EracunSyncService syncService) {
        this.cfg = cfg;
        this.syncService = syncService;

        this.exec = Executors.newScheduledThreadPool(2, new ThreadFactory() {
            private final AtomicInteger n = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "eracun-process-sync-" + n.getAndIncrement());
                t.setDaemon(true);
                return t;
            }
        });

        this.connectionSupplier = new Supplier<Connection>() {
			@Override
			public Connection get() {
				try {
					return new __Pool(null).getConnection();
				} catch (Exception ex) {
					logger.error(new Functions().logging(ex));
					throw new RuntimeException("Ne mogu dobiti Connection iz __Pool", ex);
				}
			}
		};
    }

    public synchronized void start() {
        long delay = safe(cfg.processInitialDelaySeconds(), 10L);

        if (isProcessInboxEnabled()) {
            long period = safe(getProcessInboxPeriodSeconds(), 20L);
            inboxFuture = exec.scheduleAtFixedRate(
                    new ProcessStatusJob(syncService, ProcessStatusJob.INBOX, connectionSupplier),
                    delay,
                    period,
                    TimeUnit.SECONDS
            );
            logger.info("ProcessStatus INBOX scheduler STARTED (delay=" + delay + "s, period=" + period + "s)");
        } else {
            logger.info("ProcessStatus INBOX scheduler DISABLED");
        }

        if (isProcessOutboxEnabled()) {
            long period = safe(getProcessOutboxPeriodSeconds(), 20L);
            outboxFuture = exec.scheduleAtFixedRate(
                    new ProcessStatusJob(syncService, ProcessStatusJob.OUTBOX, connectionSupplier),
                    delay,
                    period,
                    TimeUnit.SECONDS
            );
            logger.info("ProcessStatus OUTBOX scheduler STARTED (delay=" + delay + "s, period=" + period + "s)");
        } else {
            logger.info("ProcessStatus OUTBOX scheduler DISABLED");
        }
    }

    public synchronized void stop() {
        try {
            if (inboxFuture != null) {
                inboxFuture.cancel(false);
                inboxFuture = null;
            }
        } catch (Exception ex) {
            logger.error(new Functions().logging(ex));
        }
        try {
            if (outboxFuture != null) {
                outboxFuture.cancel(false);
                outboxFuture = null;
            }
        } catch (Exception ex) {
            logger.error(new Functions().logging(ex));
        }
        exec.shutdownNow();
        logger.info("ProcessStatus scheduler STOPPED");
    }

    private static long safe(Long v, long def) {
        return v != null && v > 0 ? v : def;
    }

    // Ovi "getteri" su izolirani da se ne razbije build ako cfg trenutno nema nove metode.
    private boolean isProcessInboxEnabled() {
        try { return (Boolean) EracunSyncConfig.class.getMethod("processInboxEnabled").invoke(cfg); }
        catch (Exception ignore) { return true; } // default: enabled
    }

    private boolean isProcessOutboxEnabled() {
        try { return (Boolean) EracunSyncConfig.class.getMethod("processOutboxEnabled").invoke(cfg); }
        catch (Exception ignore) { return true; } // default: enabled
    }

    private long getProcessInboxPeriodSeconds() {
        try { return (Long) EracunSyncConfig.class.getMethod("processInboxPeriodSeconds").invoke(cfg); }
        catch (Exception ignore) { return 30L; } // default: 30s
    }

    private long getProcessOutboxPeriodSeconds() {
        try { return (Long) EracunSyncConfig.class.getMethod("processOutboxPeriodSeconds").invoke(cfg); }
        catch (Exception ignore) { return 30L; } // default: 30s
    }
}