package dev.photosync.core.provider;

import java.util.List;

/**
 * The seam between PhotoSync and whatever is storing the photos.
 *
 * <p>Every method is blocking and is only ever called off the render thread, by
 * the upload workers or the timeline loader. Implementations must be safe to
 * call from several threads at once.
 *
 * <p>The interface is deliberately narrow and read-mostly. PhotoSync uploads,
 * and it browses; it does not delete, favourite or move remote assets, so no
 * such capability is exposed here. Keeping it that way is what makes a second
 * backend a weekend's work instead of a rewrite.
 */
public interface PhotoProvider extends AutoCloseable {

    ProviderDescriptor descriptor();

    /**
     * Verifies that the endpoint answers and the credentials are accepted.
     *
     * @throws ProviderException with {@link ProviderException.Kind#AUTHENTICATION}
     *         if the secret is wrong, or {@link ProviderException.Kind#NETWORK}
     *         if the endpoint cannot be reached
     */
    ProviderIdentity identify() throws ProviderException;

    /** Albums the account can upload into, for the settings picker. */
    List<Album> albums() throws ProviderException;

    Album createAlbum(String name) throws ProviderException;

    /**
     * Uploads one file and, when {@link UploadRequest#album()} names an album,
     * puts it there.
     *
     * <p>Must be idempotent with respect to file content: re-uploading bytes the
     * backend already has has to succeed with
     * {@link UploadReceipt.Outcome#DUPLICATE} rather than fail or duplicate.
     * The upload queue leans on this when it retries a job whose response was
     * lost -- for instance because the game was killed mid-request.
     */
    UploadReceipt upload(UploadRequest request, TransferProgress progress) throws ProviderException;

    /**
     * Every bucket of the timeline with its asset count, newest first.
     *
     * <p>One cheap call that gives the browser enough to size its scrollbar for
     * the entire album without fetching any asset.
     */
    List<TimelineBucket> timeline(AlbumRef album) throws ProviderException;

    /** The assets of a single bucket returned by {@link #timeline(AlbumRef)}. */
    BucketPage page(AlbumRef album, TimelineBucket bucket) throws ProviderException;

    /**
     * Encoded image bytes for one asset.
     *
     * <p>Must be PNG or JPEG. The game decodes these with stb_image, which reads
     * neither WebP nor AVIF, so a backend that stores those has to transcode or
     * ask for a different rendition -- the mod cannot recover from it later.
     */
    byte[] thumbnail(String assetId, ThumbnailSize size) throws ProviderException;

    /** Releases connections. Never throws, so callers can use try-with-resources cleanly. */
    @Override
    void close();
}
