package com.atlassian.bitbucket.rest.hook.repository;

import com.atlassian.bitbucket.rest.util.RestPage;
import com.atlassian.bitbucket.hook.repository.RepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookDetails;
import com.atlassian.bitbucket.hook.repository.RepositoryHookType;
import com.atlassian.bitbucket.rest.annotation.JsonSurrogate;
import com.atlassian.bitbucket.rest.RestMapEntity;
import org.codehaus.jackson.map.annotate.JsonSerialize;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.util.Map;
import java.util.function.Function;

import static com.atlassian.bitbucket.rest.util.RestDocUtils.pageOf;
import static com.google.common.base.Preconditions.checkNotNull;

@JsonSerialize
@JsonSurrogate(RepositoryHook.class)
public class RestRepositoryHook extends RestMapEntity implements RepositoryHook {

    private static final String DETAILS = "details";
    private static final String ENABLED = "enabled";
    private static final String CONFIGURED = "configured";

    public static final Function<RepositoryHook, RestRepositoryHook> REST_TRANSFORM = RestRepositoryHook::new;

    public RestRepositoryHook(RestRepositoryHookDetails details, boolean isEnabled, boolean configured) {
        put(DETAILS, details);
        put(ENABLED, isEnabled);
        put(CONFIGURED, configured);
    }

    public RestRepositoryHook(RepositoryHook descriptor) {
        this(new RestRepositoryHookDetails(descriptor.getDetails()), descriptor.isEnabled(), descriptor.isConfigured());
    }

    @Nonnull
    @Override
    public RepositoryHookDetails getDetails() {
        Object details = checkNotNull(get(DETAILS), "details");
        if (details instanceof RepositoryHookDetails) {
            return (RepositoryHookDetails) details;
        } else if (details instanceof Map) {
            return new RestRepositoryHookDetails((Map<String, Object>) details);
        }
        throw new IllegalStateException("details of type " + details.getClass().getName() + " are not supported");
    }

    @Override
    public boolean isEnabled() {
        return getBoolProperty(ENABLED);
    }

    @Override
    public boolean isConfigured() {
        return getBoolProperty(CONFIGURED);
    }

    // REST Documentation Examples

    public static final RestRepositoryHook EXAMPLE = new RestRepositoryHook(
            new RestRepositoryHookDetails(
                    "com.atlassian.stash.plugin.example:example-repository-hook",
                    "Example repository hook",
                    RepositoryHookType.PRE_RECEIVE,
                    "An example description for an example hook.",
                    "1.2.4",
                    null),
            true,
            true
    );

    public static final RestPage<RestRepositoryHook> PAGE_EXAMPLE = pageOf(EXAMPLE);

    @JsonSerialize
    private static class RestRepositoryHookDetails extends RestMapEntity implements RepositoryHookDetails {

        private static final String KEY = "key";
        private static final String NAME = "name";
        private static final String TYPE = "type";
        private static final String DESCRIPTION = "description";
        private static final String VERSION = "version";
        private static final String CONFIG_FORM_KEY = "configFormKey";

        private RestRepositoryHookDetails(Map<String, Object> map) {
            super(map);
        }

        public RestRepositoryHookDetails(RepositoryHookDetails details) {
            this(
                    details.getKey(),
                    details.getName(),
                    details.getType(),
                    details.getDescription(),
                    details.getVersion(),
                    details.getConfigFormKey()
            );
        }

        // Required for REST documentation
        private RestRepositoryHookDetails(
                String key,
                String name,
                RepositoryHookType type,
                String description,
                String version,
                String configFormKey) {

            put(KEY, key);
            put(NAME, name);
            put(TYPE, type);
            put(DESCRIPTION, description);
            put(VERSION, version);
            put(CONFIG_FORM_KEY, configFormKey);
        }

        @Override
        public String getKey() {
            return getStringProperty(KEY);
        }

        @Override
        public String getName() {
            return getStringProperty(NAME);
        }

        @Override
        public RepositoryHookType getType() {
            return getEnumProperty(TYPE, RepositoryHookType.class);
        }

        @Nullable
        @Override
        public String getDescription() {
            return getStringProperty(DESCRIPTION);
        }

        @Override
        public String getVersion() {
            return getStringProperty(VERSION);
        }

        @Nullable
        @Override
        public String getConfigFormKey() {
            return getStringProperty(CONFIG_FORM_KEY);
        }

    }
}