package com.atlassian.bitbucket.internal.mirroring.upstream.dao;

import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Date;

/**
 * The DAO for persisting {@link AoMirrorServer mirrors}
 */
public interface MirrorServerDao {
    /**
     * Creates a new mirror
     *
     * @param id the unique ID of the mirror
     * @param addonKey  the key of the connect add-on that represents the mirror server
     * @param baseUrl the mirror's base URL
     * @param name the non-unique name of the mirror
     * @param productType the type of the software product that runs the mirror
     * @param productVersion the version of the software product that runs the mirror
     * @param enabled whether the mirror is enabled
     * @return the newly-created mirror
     */
    @Nonnull
    AoMirrorServer create(@Nonnull String id, @Nonnull String addonKey,
                          @Nonnull String baseUrl, @Nonnull String name,
                          @Nonnull String productType, @Nonnull String productVersion,
                          boolean enabled);

    /**
     * Deletes a mirror instance
     * @param mirror the instance to delete
     */
    void delete(@Nonnull AoMirrorServer mirror);

    /**
     * @param pageRequest describes the page of mirrors to retrieve
     * @return a page of mirrors
     */
    @Nonnull
    Page<AoMirrorServer> findAll(@Nonnull PageRequest pageRequest);

    /**
     * @param addonKey the add-on key for the mirror server
     * @return the matching mirror server or {@code null} if not found
     */
    @Nullable
    AoMirrorServer getByAddonKey(@Nonnull String addonKey);

    /**
     * @param id the id of the mirror
     * @return a mirror with the corresponding ID or {@code null} if no such mirror was found
     */
    @Nullable
    AoMirrorServer getById(@Nonnull String id);

    /**
     * @return {@code true} if at least one mirror exists, {@code false} otherwise
     */
    boolean hasMirror();

    /**
     * Transitions the state of the mirror server, optionally updating the {@code lastSeen} field.
     *
     * @param id the ID of the mirror
     * @param enabled the new state of the mirror
     * @param lastSeen if non-null, indicates the new {@link AoMirrorServer#getLastSeenDate() lastSeen} value which should be updated
     * @return the mirror
     * @throws IllegalArgumentException if no mirror with that ID was found
     */
    @Nonnull
    AoMirrorServer transitionState(@Nonnull String id, boolean enabled, @Nullable Date lastSeen);

    /**
     * Transitions the state of the mirror server, optionally updating the {@code lastSeen} field.
     *
     * @param mirror the mirror
     * @param enabled the new state of the mirror
     * @param lastSeen if non-null, indicates the new {@link AoMirrorServer#getLastSeenDate() lastSeen} value which
     *                 should be updated
     * @return the mirror
     * @throws IllegalArgumentException if no mirror with that ID was found
     */
    @Nonnull
    AoMirrorServer transitionState(@Nonnull AoMirrorServer mirror, boolean enabled, @Nullable Date lastSeen);
}
