package ru.yandex.qe.dispenser.domain.dictionaries.model;

import java.util.List;
import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ru.yandex.qe.dispenser.api.v1.DiAmount;
import ru.yandex.qe.dispenser.api.v1.DiCampaign;
import ru.yandex.qe.dispenser.api.v1.DiResourceType;
import ru.yandex.qe.dispenser.domain.ResourceUnit;

public final class CampaignProvidersSettingsDictionary {

    @NotNull
    private final DiCampaign campaign;
    @NotNull
    private final List<Segmentation> segmentations;
    @NotNull
    private final List<Provider> providers;

    @JsonCreator
    public CampaignProvidersSettingsDictionary(@NotNull @JsonProperty("campaign") final DiCampaign campaign,
                                               @NotNull @JsonProperty("segmentations") final List<Segmentation> segmentations,
                                               @NotNull @JsonProperty("providers") final List<Provider> providers) {
        this.campaign = campaign;
        this.segmentations = segmentations;
        this.providers = providers;
    }

    @NotNull
    public DiCampaign getCampaign() {
        return campaign;
    }

    @NotNull
    public List<Segmentation> getSegmentations() {
        return segmentations;
    }

    @NotNull
    public List<Provider> getProviders() {
        return providers;
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final CampaignProvidersSettingsDictionary that = (CampaignProvidersSettingsDictionary) o;
        return campaign.equals(that.campaign) &&
                segmentations.equals(that.segmentations) &&
                providers.equals(that.providers);
    }

    @Override
    public int hashCode() {
        return Objects.hash(campaign, segmentations, providers);
    }

    @Override
    public String toString() {
        return "CampaignProvidersSettingsDictionary{" +
                "campaign=" + campaign +
                ", segmentations=" + segmentations +
                ", providers=" + providers +
                '}';
    }

    public static final class Segmentation {

        private final long id;
        @NotNull
        private final String key;
        @NotNull
        private final String name;
        @NotNull
        private final List<Segment> segments;
        private int priority;

        @JsonCreator
        public Segmentation(@JsonProperty("id") final long id,
                            @NotNull @JsonProperty("key") final String key,
                            @NotNull @JsonProperty("name") final String name,
                            @NotNull @JsonProperty("segments") final List<Segment> segments,
                            @JsonProperty("priority") final int priority) {
            this.id = id;
            this.key = key;
            this.name = name;
            this.segments = segments;
            this.priority = priority;
        }

        public long getId() {
            return id;
        }

        @NotNull
        public String getKey() {
            return key;
        }

        @NotNull
        public String getName() {
            return name;
        }

        @NotNull
        public List<Segment> getSegments() {
            return segments;
        }

        public int getPriority() {
            return priority;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Segmentation that = (Segmentation) o;
            return id == that.id &&
                    priority == that.priority &&
                    key.equals(that.key) &&
                    name.equals(that.name) &&
                    segments.equals(that.segments);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, key, name, segments, priority);
        }

        @Override
        public String toString() {
            return "Segmentation{" +
                    "id=" + id +
                    ", key='" + key + '\'' +
                    ", name='" + name + '\'' +
                    ", segments=" + segments +
                    ", priority=" + priority +
                    '}';
        }

    }

    public static final class Segment {
        private final long id;
        @NotNull
        private final String key;
        @NotNull
        private final String name;
        private final short priority;

        @JsonCreator
        public Segment(@JsonProperty("id") final long id,
                       @NotNull @JsonProperty("key") final String key,
                       @NotNull @JsonProperty("name") final String name,
                       @JsonProperty("priority") final short priority) {
            this.id = id;
            this.key = key;
            this.name = name;
            this.priority = priority;
        }

        public long getId() {
            return id;
        }

        @NotNull
        public String getKey() {
            return key;
        }

        @NotNull
        public String getName() {
            return name;
        }

        public short getPriority() {
            return priority;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Segment segment = (Segment) o;
            return id == segment.id &&
                    priority == segment.priority &&
                    key.equals(segment.key) &&
                    name.equals(segment.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, key, name, priority);
        }

        @Override
        public String toString() {
            return "Segment{" +
                    "id=" + id +
                    ", key='" + key + '\'' +
                    ", name='" + name + '\'' +
                    ", priority=" + priority +
                    '}';
        }

    }

    public static final class Provider {

        private final long id;
        @NotNull
        private final String key;
        @NotNull
        private final String name;
        @Nullable
        private final Integer priority;
        @NotNull
        private final List<Resource> resources;
        @NotNull
        private final List<ResourcePreset> defaultResources;

        @JsonCreator
        public Provider(@JsonProperty("id") final long id,
                        @NotNull @JsonProperty("key") final String key,
                        @NotNull @JsonProperty("name") final String name,
                        @Nullable @JsonProperty("priority") final Integer priority,
                        @NotNull @JsonProperty("resources") final List<Resource> resources,
                        @NotNull @JsonProperty("defaultResources") final List<ResourcePreset> defaultResources) {
            this.id = id;
            this.key = key;
            this.name = name;
            this.priority = priority;
            this.resources = resources;
            this.defaultResources = defaultResources;
        }

        public long getId() {
            return id;
        }

        @NotNull
        public String getKey() {
            return key;
        }

        @NotNull
        public String getName() {
            return name;
        }

        @Nullable
        @JsonInclude(JsonInclude.Include.NON_NULL)
        public Integer getPriority() {
            return priority;
        }

        @NotNull
        public List<Resource> getResources() {
            return resources;
        }

        public List<ResourcePreset> getDefaultResources() {
            return defaultResources;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Provider provider = (Provider) o;
            return id == provider.id &&
                    key.equals(provider.key) &&
                    name.equals(provider.name) &&
                    Objects.equals(priority, provider.priority) &&
                    resources.equals(provider.resources) &&
                    defaultResources.equals(provider.defaultResources);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, key, name, priority, resources, defaultResources);
        }

        @Override
        public String toString() {
            return "Provider{" +
                    "id=" + id +
                    ", key='" + key + '\'' +
                    ", name='" + name + '\'' +
                    ", priority=" + priority +
                    ", resources=" + resources +
                    ", defaultResources=" + defaultResources +
                    '}';
        }

    }

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public static final class Resource {

        private final long id;
        @NotNull
        private final String key;
        @NotNull
        private final String name;
        @NotNull
        private final DiResourceType type;
        private final boolean required;
        private final boolean defaultResource;
        @Nullable
        private final DiAmount defaultAmount;
        @Nullable
        private final Integer priority;
        private final List<ResourceSegmentation> segmentations;
        private final List<Long> bigOrders;
        private final List<SegmentsBigOrders> segmentedBigOrders;

        @Nullable
        private final String defaultUnit;
        @Nullable
        private final ResourceUnit.UnitsSettings units;

        @JsonCreator
        public Resource(@JsonProperty("id") final long id,
                        @NotNull @JsonProperty("key") final String key,
                        @NotNull @JsonProperty("name") final String name,
                        @NotNull @JsonProperty("type") final DiResourceType type,
                        @JsonProperty("required") final boolean required,
                        @JsonProperty("default") final boolean defaultResource,
                        @Nullable @JsonProperty("defaultAmount") final DiAmount defaultAmount,
                        @Nullable @JsonProperty("priority") final Integer priority,
                        @JsonProperty("segmentations") final List<ResourceSegmentation> segmentations,
                        @JsonProperty("bigOrders") final List<Long> bigOrders,
                        @JsonProperty("segmentedBigOrders") final List<SegmentsBigOrders> segmentedBigOrders,
                        @Nullable @JsonProperty("defaultUnit") final String defaultUnit,
                        @Nullable @JsonProperty("units") final ResourceUnit.UnitsSettings units) {
            this.id = id;
            this.key = key;
            this.name = name;
            this.type = type;
            this.required = required;
            this.defaultResource = defaultResource;
            this.defaultAmount = defaultAmount;
            this.priority = priority;
            this.segmentations = segmentations;
            this.bigOrders = bigOrders;
            this.segmentedBigOrders = segmentedBigOrders;
            this.defaultUnit = defaultUnit;
            this.units = units;
        }

        public long getId() {
            return id;
        }

        @NotNull
        public String getKey() {
            return key;
        }

        @NotNull
        public String getName() {
            return name;
        }

        @NotNull
        public DiResourceType getType() {
            return type;
        }

        public boolean isRequired() {
            return required;
        }

        @JsonProperty("default")
        public boolean isDefaultResource() {
            return defaultResource;
        }

        @Nullable
        @JsonInclude(JsonInclude.Include.NON_NULL)
        public DiAmount getDefaultAmount() {
            return defaultAmount;
        }

        @Nullable
        @JsonInclude(JsonInclude.Include.NON_NULL)
        public Integer getPriority() {
            return priority;
        }

        public List<ResourceSegmentation> getSegmentations() {
            return segmentations;
        }

        public List<Long> getBigOrders() {
            return bigOrders;
        }

        public List<SegmentsBigOrders> getSegmentedBigOrders() {
            return segmentedBigOrders;
        }

        @Nullable
        public String getDefaultUnit() {
            return defaultUnit;
        }

        @Nullable
        public ResourceUnit.UnitsSettings getUnits() {
            return units;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Resource resource = (Resource) o;
            return id == resource.id &&
                    required == resource.required &&
                    defaultResource == resource.defaultResource &&
                    key.equals(resource.key) &&
                    name.equals(resource.name) &&
                    type == resource.type &&
                    Objects.equals(defaultAmount, resource.defaultAmount) &&
                    Objects.equals(priority, resource.priority) &&
                    Objects.equals(segmentations, resource.segmentations) &&
                    Objects.equals(bigOrders, resource.bigOrders) &&
                    Objects.equals(segmentedBigOrders, resource.segmentedBigOrders) &&
                    Objects.equals(defaultUnit, resource.defaultUnit) &&
                    Objects.equals(units, resource.units);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, key, name, type, required, defaultResource, defaultAmount, priority, segmentations, bigOrders, segmentedBigOrders, defaultUnit, units);
        }

        @Override
        public String toString() {
            return "Resource{" +
                    "id=" + id +
                    ", key='" + key + '\'' +
                    ", name='" + name + '\'' +
                    ", type=" + type +
                    ", required=" + required +
                    ", defaultResource=" + defaultResource +
                    ", defaultAmount=" + defaultAmount +
                    ", priority=" + priority +
                    ", segmentations=" + segmentations +
                    ", bigOrders=" + bigOrders +
                    ", segmentedBigOrders=" + segmentedBigOrders +
                    ", defaultUnit='" + defaultUnit + '\'' +
                    ", units=" + units +
                    '}';
        }

    }

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public static final class ResourceSegmentation {

        private final long id;
        private final List<Long> segments;

        @JsonCreator
        public ResourceSegmentation(@JsonProperty("id") final long id,
                                    @JsonProperty("segments") final List<Long> segments) {
            this.id = id;
            this.segments = segments;
        }

        public long getId() {
            return id;
        }

        public List<Long> getSegments() {
            return segments;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final ResourceSegmentation that = (ResourceSegmentation) o;
            return id == that.id &&
                    Objects.equals(segments, that.segments);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, segments);
        }

        @Override
        public String toString() {
            return "ResourceSegmentation{" +
                    "id=" + id +
                    ", segments=" + segments +
                    '}';
        }

    }

    public static final class SegmentsBigOrders {

        @NotNull
        private final List<Long> segments;
        @NotNull
        private final List<Long> bigOrders;

        @JsonCreator
        public SegmentsBigOrders(@NotNull @JsonProperty("segments") final List<Long> segments,
                                 @NotNull @JsonProperty("bigOrders") final List<Long> bigOrders) {
            this.segments = segments;
            this.bigOrders = bigOrders;
        }

        @NotNull
        public List<Long> getSegments() {
            return segments;
        }

        @NotNull
        public List<Long> getBigOrders() {
            return bigOrders;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final SegmentsBigOrders that = (SegmentsBigOrders) o;
            return segments.equals(that.segments) &&
                    bigOrders.equals(that.bigOrders);
        }

        @Override
        public int hashCode() {
            return Objects.hash(segments, bigOrders);
        }

        @Override
        public String toString() {
            return "SegmentsBigOrders{" +
                    "segments=" + segments +
                    ", bigOrders=" + bigOrders +
                    '}';
        }

    }

    public static final class ResourcePreset {

        private final long resourceId;
        @NotNull
        private final List<ResourcePresetSegment> segments;

        public ResourcePreset(@JsonProperty("resourceId") final long resourceId,
                              @NotNull @JsonProperty("segments") final List<ResourcePresetSegment> segments) {
            this.resourceId = resourceId;
            this.segments = segments;
        }

        public long getResourceId() {
            return resourceId;
        }

        @NotNull
        public List<ResourcePresetSegment> getSegments() {
            return segments;
        }
    }

    public static final class ResourcePresetSegment {
        private final long segmentationId;
        private final long segmentId;

        public ResourcePresetSegment(@JsonProperty("segmentationId") final long segmentationId,
                                     @JsonProperty("segmentId") final long segmentId) {
            this.segmentationId = segmentationId;
            this.segmentId = segmentId;
        }

        public long getSegmentationId() {
            return segmentationId;
        }

        public long getSegmentId() {
            return segmentId;
        }
    }

}
