package cn.ibizlab.codegen.config;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class GeneratorSettings implements Serializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(GeneratorSettings.class);
    private static final String DEFAULT_GIT_HOST = "github.com";
    private static final String DEFAULT_GIT_USER_ID = "GIT_USER_ID";
    private static final String DEFAULT_GIT_REPO_ID = "GIT_REPO_ID";
    private static final String DEFAULT_RELEASE_NOTE = "Minor update";


    private String projectName;
    private String packageName;

    private Map<String, Object> additionalProperties = new LinkedHashMap<>();


    private String gitHost;
    private String gitUserId;
    private String gitRepoId;
    private String releaseNote;
    private String httpUserAgent;

    private Map<String, String> typeMappings;


    public String getHost()
    {
        return gitHost+"abc";
    }


    private GeneratorSettings(Builder builder) {
        projectName = builder.projectName;
        packageName = builder.packageName;
        typeMappings = Collections.unmodifiableMap(builder.typeMappings);
        gitHost = builder.gitHost;
        gitUserId = builder.gitUserId;
        gitRepoId = builder.gitRepoId;
        releaseNote = builder.releaseNote;
        httpUserAgent = builder.httpUserAgent;
        Map<String, Object> additional = new HashMap<>(builder.additionalProperties);
        additionalProperties = Collections.unmodifiableMap(additional);
    }

    public static Builder newBuilder(GeneratorSettings copy) {
        Builder builder = new Builder();
        builder.projectName = copy.projectName;
        builder.packageName = copy.packageName;
        builder.typeMappings = Collections.unmodifiableMap(copy.typeMappings);
        builder.gitHost = copy.gitHost;
        builder.gitUserId = copy.gitUserId;
        builder.gitRepoId = copy.gitRepoId;
        builder.releaseNote = copy.releaseNote;
        builder.httpUserAgent = copy.httpUserAgent;
        Map<String, Object> additional = new HashMap<>(copy.additionalProperties);
        builder.additionalProperties = Collections.unmodifiableMap(additional);
        return builder;
    }

    public static final class Builder {

        private String projectName;
        private String packageName;
        private String gitHost;
        private String gitUserId;
        private String gitRepoId;
        private String releaseNote;
        private String httpUserAgent;

        private Map<String, String> typeMappings;
        private Map<String, Object> additionalProperties;



        /**
         * Instantiates a new Builder.
         */
        public Builder() {
            typeMappings = new HashMap<>();
            additionalProperties = new HashMap<>();
            gitHost = DEFAULT_GIT_HOST;
            gitUserId = DEFAULT_GIT_USER_ID;
            gitRepoId = DEFAULT_GIT_REPO_ID;
            releaseNote = DEFAULT_RELEASE_NOTE;
        }

        public Builder withProjectName(String projectName) {
            this.projectName = projectName;
            return this;
        }

        /**
         * Sets the {@code packageName} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param packageName the {@code packageName} to set
         * @return a reference to this Builder
         */
        public Builder withPackageName(String packageName) {
            this.packageName = packageName;
            return this;
        }



        /**
         * Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param typeMappings the {@code typeMappings} to set
         * @return a reference to this Builder
         */
        public Builder withTypeMappings(Map<String, String> typeMappings) {
            this.typeMappings = typeMappings;
            return this;
        }

        public Builder withTypeMapping(String key, String value) {
            if (this.typeMappings == null) {
                this.typeMappings = new HashMap<>();
            }
            this.typeMappings.put(key, value);
            return this;
        }

        /**
         * Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param additionalProperties the {@code additionalProperties} to set
         * @return a reference to this Builder
         */
        public Builder withAdditionalProperties(Map<String, Object> additionalProperties) {
            this.additionalProperties = additionalProperties;
            return this;
        }

        /**
         * Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param key   A key for some additional property
         * @param value The value of some additional property
         * @return a reference to this Builder
         */
        public Builder withAdditionalProperty(String key, Object value) {
            if (this.additionalProperties == null) {
                this.additionalProperties = new HashMap<>();
            }
            this.additionalProperties.put(key, value);
            return this;
        }


        /**
         * Sets the {@code gitHost} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param gitHost the {@code gitHost} to set
         * @return a reference to this Builder
         */
        public Builder withGitHost(String gitHost) {
            this.gitHost = gitHost;
            return this;
        }

        /**
         * Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param gitUserId the {@code gitUserId} to set
         * @return a reference to this Builder
         */
        public Builder withGitUserId(String gitUserId) {
            this.gitUserId = gitUserId;
            return this;
        }

        /**
         * Sets the {@code gitRepoId} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param gitRepoId the {@code gitRepoId} to set
         * @return a reference to this Builder
         */
        public Builder withGitRepoId(String gitRepoId) {
            this.gitRepoId = gitRepoId;
            return this;
        }

        /**
         * Sets the {@code releaseNote} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param releaseNote the {@code releaseNote} to set
         * @return a reference to this Builder
         */
        public Builder withReleaseNote(String releaseNote) {
            this.releaseNote = releaseNote;
            return this;
        }

        /**
         * Sets the {@code httpUserAgent} and returns a reference to this Builder so that the methods can be chained together.
         *
         * @param httpUserAgent the {@code httpUserAgent} to set
         * @return a reference to this Builder
         */
        public Builder withHttpUserAgent(String httpUserAgent) {
            this.httpUserAgent = httpUserAgent;
            return this;
        }

        /**
         * Returns a {@code GeneratorSettings} built from the parameters previously set.
         *
         * @return a {@code GeneratorSettings} built with parameters of this {@code GeneratorSettings.Builder}
         */
        public GeneratorSettings build() {
            GeneratorSettings instance = new GeneratorSettings(this);
            //noinspection PlaceholderCountMatchesArgumentCount
            LOGGER.debug("GeneratorSettings#build: %s", instance.toString());
            return instance;
        }
    }

}
