package dev.photosync.core.provider;

import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.Optional;

/**
 * The one live {@link PhotoProvider}, rebuilt whenever the credentials change.
 *
 * <p>Uploads and browsing share it, so they also share its connection pool
 * rather than each opening their own. It knows nothing about the config file --
 * it is <em>told</em> to reconfigure -- which keeps the provider package free of
 * a dependency on the config package.
 */
@Slf4j
public final class ProviderSession implements AutoCloseable {

    private final ProviderCatalog catalog;
    private final Object lock = new Object();

    private ProviderId currentId;
    private ProviderConnection currentConnection = ProviderConnection.empty();
    private PhotoProvider provider;

    public ProviderSession(ProviderCatalog catalog) {
        this.catalog = catalog;
        this.currentId = catalog.preferred();
    }

    /** Cheap and idempotent: unchanged credentials leave the provider alone. */
    public void configure(ProviderId id, ProviderConnection connection) {
        PhotoProvider discarded = null;
        synchronized (lock) {
            if (Objects.equals(currentId, id) && Objects.equals(currentConnection, connection)) {
                return;
            }
            discarded = provider;
            currentId = id;
            currentConnection = connection;
            provider = connection.isConfigured() ? catalog.connect(id, connection) : null;
        }
        if (discarded != null) {
            closeQuietly(discarded);
        }
    }

    /** Empty until the player has entered a server and a key. */
    public Optional<PhotoProvider> provider() {
        synchronized (lock) {
            return Optional.ofNullable(provider);
        }
    }

    public boolean isConfigured() {
        synchronized (lock) {
            return provider != null;
        }
    }

    /**
     * A throwaway provider for the settings screen's "test connection" button,
     * so the player can check credentials before committing them.
     */
    public PhotoProvider probe(ProviderId id, ProviderConnection connection) {
        return catalog.connect(id, connection);
    }

    @Override
    public void close() {
        PhotoProvider discarded;
        synchronized (lock) {
            discarded = provider;
            provider = null;
        }
        if (discarded != null) {
            closeQuietly(discarded);
        }
    }

    private static void closeQuietly(PhotoProvider target) {
        try {
            target.close();
        } catch (RuntimeException e) {
            log.debug("Closing a provider threw", e);
        }
    }
}
