package io.delphiplatform.api.v3.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;

import org.openapitools.jackson.nullable.JsonNullable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDate;
import java.util.Objects;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import io.delphiplatform.api.v3.model.amazon.AmazonStreamsInfo;
import io.delphiplatform.api.v3.model.apple.AppleStreamsInfo;
import io.delphiplatform.api.v3.model.spotify.SpotifyStreamsInfo;

/**
 * Stream
 */
@Validated
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
public class StreamModel {

    @JsonProperty("artist_id")
    private String artistId;

    @JsonProperty("country_code")
    private String countryCode;

    @JsonProperty("date")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate date;

    @JsonProperty("dsp")
    public String getDsp() {
        return subDsp == null ? mainDsp : subDsp;
    }

    @JsonIgnore
    private String mainDsp;

    @JsonIgnore
    private String subDsp;

    @JsonIgnore
    private Boolean hasStationStreams;

    @JsonProperty("isrc")
    private String isrc;

    @JsonProperty("playlist_id")
    private String playlistId;

    @JsonProperty("streams")
    private Long streams;

    @JsonProperty("track_id")
    private String trackId;

    @JsonProperty("project_number")
    private String projectNumber;

    @JsonProperty("product_family_id")
    private String productFamilyId;

    @JsonProperty("genders")
    private JsonNullable<Gender> genders = JsonNullable.undefined();

    @JsonProperty("apple_age_bands")
    private JsonNullable<AppleAgeBand> appleAgeBands = JsonNullable.undefined();

    @JsonProperty("spotify_age_bands")
    private JsonNullable<SpotifyAgeBand> spotifyAgeBands = JsonNullable.undefined();

    @JsonProperty("amazon_streams_info")
    private JsonNullable<AmazonStreamsInfo> amazonStreamsInfo = JsonNullable.undefined();

    @JsonProperty("spotify_streams_info")
    private JsonNullable<SpotifyStreamsInfo> spotifyStreamsInfo = JsonNullable.undefined();

    @JsonProperty("apple_streams_info")
    private JsonNullable<AppleStreamsInfo> appleStreamsInfo = JsonNullable.undefined();

    public SpotifyStreamsInfo initSpotifyStreamsInfoIfNone() {
        if (!spotifyStreamsInfo.isPresent() || spotifyStreamsInfo.get() == null) {
            spotifyStreamsInfo = JsonNullable.of(new SpotifyStreamsInfo());
        }
        return spotifyStreamsInfo.get();
    }

    public AppleStreamsInfo initAppleStreamsInfoIfNone() {
        if (!appleStreamsInfo.isPresent() || appleStreamsInfo.get() == null) {
            appleStreamsInfo = JsonNullable.of(new AppleStreamsInfo());
        }
        return appleStreamsInfo.get();
    }

    public AmazonStreamsInfo initAmazonStreamsInfoIfNone() {
        if (!amazonStreamsInfo.isPresent() || amazonStreamsInfo.get() == null) {
            amazonStreamsInfo = JsonNullable.of(new AmazonStreamsInfo());
        }
        return amazonStreamsInfo.get();
    }

    public StreamModel date(LocalDate date) {
        this.date = date;
        return this;
    }

    /**
     * ISO 8601 date in format `YYYY-MM-DD`
     *
     * @return date
     */
    @Valid
    @Pattern(regexp = "^\\d{4}-\\d{2}-\\d{2}$")
    public LocalDate getDate() {
        return date;
    }

    public void setDate(LocalDate date) {
        this.date = date;
    }

    public StreamModel mainDsp(String mainDsp) {
        this.mainDsp = mainDsp;
        return this;
    }

    /**
     * Slug name of a DSP
     *
     * @return dsp
     */
    @Pattern(regexp = "^[a-z]*$")
    public String getMainDsp() {
        return mainDsp;
    }

    public void setMainDsp(String mainDsp) {
        this.mainDsp = mainDsp;
    }


    public StreamModel subDsp(String subDsp) {
        this.subDsp = subDsp;
        return this;
    }

    public String getSubDsp() {
        return subDsp;
    }

    public void setSubDsp(String subDsp) {
        this.subDsp = subDsp;
    }

    public StreamModel hasStationStreams(Boolean hasStationStreams) {
        this.hasStationStreams = hasStationStreams;
        return this;
    }

    public Boolean hasStationStreams() {
        return hasStationStreams;
    }

    public void setHasStationStreams(Boolean hasStationStreams) {
        this.hasStationStreams = hasStationStreams;
    }

    public StreamModel countryCode(String countryCode) {
        this.countryCode = countryCode;
        return this;
    }

    /**
     * Typically a lower-case two letter code for the country
     *
     * @return countryCode
     */
    @NotNull
    public String getCountryCode() {
        return countryCode;
    }

    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }

    public StreamModel streams(Long streams) {
        this.streams = streams;
        return this;
    }

    /**
     * The number of streams, aggregated by provided filter parameters.
     *
     * @return streams
     */
    @NotNull
    public Long getStreams() {
        return streams;
    }

    public void setStreams(Long streams) {
        this.streams = streams;
    }

    public StreamModel artistId(String artistId) {
        this.artistId = artistId;
        return this;
    }

    /**
     * Primary key identifier for Artist
     *
     * @return artistId
     */
    public String getArtistId() {
        return artistId;
    }

    public void setArtistId(String artistId) {
        this.artistId = artistId;
    }

    public StreamModel trackId(String trackId) {
        this.trackId = trackId;
        return this;
    }

    /**
     * Primary key identifier for Track
     *
     * @return trackId
     */
    public String getTrackId() {
        return trackId;
    }

    public void setTrackId(String trackId) {
        this.trackId = trackId;
    }

    public StreamModel playlistId(String playlistId) {
        this.playlistId = playlistId;
        return this;
    }

    /**
     * Primary key identifier for Playlist
     *
     * @return playlistId
     */
    public String getPlaylistId() {
        return playlistId;
    }

    public void setPlaylistId(String playlistId) {
        this.playlistId = playlistId;
    }

    public StreamModel isrc(String isrc) {
        this.isrc = isrc;
        return this;
    }

    /**
     * The International Standard Recording Code (ISRC) for a song.
     *
     * @return isrc
     */
    public String getIsrc() {
        return isrc;
    }

    public void setIsrc(String isrc) {
        this.isrc = isrc;
    }

    public StreamModel appleAgeBands(AppleAgeBand appleAgeBands) {
        this.appleAgeBands = JsonNullable.of(appleAgeBands);
        return this;
    }

    /**
     * Get appleAgeBands
     *
     * @return appleAgeBands
     */
    @Valid
    public JsonNullable<AppleAgeBand> getAppleAgeBands() {
        return appleAgeBands;
    }

    public void setAppleAgeBands(JsonNullable<AppleAgeBand> appleAgeBands) {
        this.appleAgeBands = appleAgeBands;
    }

    public StreamModel spotifyAgeBands(SpotifyAgeBand spotifyAgeBands) {
        this.spotifyAgeBands = JsonNullable.of(spotifyAgeBands);
        return this;
    }

    /**
     * Get spotifyAgeBands
     *
     * @return spotifyAgeBands
     */
    @Valid
    public JsonNullable<SpotifyAgeBand> getSpotifyAgeBands() {
        return spotifyAgeBands;
    }

    public void setSpotifyAgeBands(JsonNullable<SpotifyAgeBand> spotifyAgeBands) {
        this.spotifyAgeBands = spotifyAgeBands;
    }

    public StreamModel genders(Gender genders) {
        this.genders = JsonNullable.of(genders);
        return this;
    }

    /**
     * Get genders
     *
     * @return genders
     */
    @Valid
    public JsonNullable<Gender> getGenders() {
        return genders;
    }

    public void setGenders(JsonNullable<Gender> genders) {
        this.genders = genders;
    }

    public StreamModel amazonStreamsInfo(AmazonStreamsInfo amazonStreamsInfo) {
        this.amazonStreamsInfo = JsonNullable.of(amazonStreamsInfo);
        return this;
    }

    public JsonNullable<AmazonStreamsInfo> getAmazonStreamsInfo() {
        return amazonStreamsInfo;
    }

    public void setAmazonStreamsInfo(JsonNullable<AmazonStreamsInfo> amazonStreamsInfo) {
        this.amazonStreamsInfo = amazonStreamsInfo;
    }

    public StreamModel spotifyStreamsInfo(SpotifyStreamsInfo spotifyStreamsInfo) {
        this.spotifyStreamsInfo = JsonNullable.of(spotifyStreamsInfo);
        return this;
    }

    public JsonNullable<SpotifyStreamsInfo> getSpotifyStreamsInfo() {
        return spotifyStreamsInfo;
    }

    public void setSpotifyStreamsInfo(JsonNullable<SpotifyStreamsInfo> spotifyStreamsInfo) {
        this.spotifyStreamsInfo = spotifyStreamsInfo;
    }

    public StreamModel appleStreamsInfo(AppleStreamsInfo appleStreamsInfo) {
        this.appleStreamsInfo = JsonNullable.of(appleStreamsInfo);
        return this;
    }

    public JsonNullable<AppleStreamsInfo> getAppleStreamsInfo() {
        return appleStreamsInfo;
    }

    public void setAppleStreamsInfo(JsonNullable<AppleStreamsInfo> appleStreamsInfo) {
        this.appleStreamsInfo = appleStreamsInfo;
    }

    public StreamModel productFamilyId(String productFamilyId) {
        this.productFamilyId = productFamilyId;
        return this;
    }

    public String getProductFamilyId() {
        return productFamilyId;
    }

    public StreamModel projectNumber(String projectNumber) {
        this.projectNumber = projectNumber;
        return this;
    }

    public String getProjectNumber() {
        return projectNumber;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        StreamModel stream = (StreamModel) o;
        return Objects.equals(this.date, stream.date) &&
            Objects.equals(this.mainDsp, stream.mainDsp) &&
            Objects.equals(this.countryCode, stream.countryCode) &&
            Objects.equals(this.streams, stream.streams) &&
            Objects.equals(this.artistId, stream.artistId) &&
            Objects.equals(this.trackId, stream.trackId) &&
            Objects.equals(this.playlistId, stream.playlistId) &&
            Objects.equals(this.isrc, stream.isrc) &&
            Objects.equals(this.appleAgeBands, stream.appleAgeBands) &&
            Objects.equals(this.spotifyAgeBands, stream.spotifyAgeBands) &&
            Objects.equals(this.hasStationStreams, stream.hasStationStreams) &&
            Objects.equals(this.genders, stream.genders);
    }

    @Override
    public int hashCode() {
        return Objects.hash(
            date,
            mainDsp,
            countryCode,
            streams,
            artistId,
            trackId,
            playlistId,
            isrc,
            appleAgeBands,
            spotifyAgeBands,
            genders,
            hasStationStreams
        );
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("class Stream {\n");

        sb.append("    date: ").append(toIndentedString(date)).append("\n");
        sb.append("    dsp: ").append(toIndentedString(mainDsp)).append("\n");
        sb.append("    countryCode: ").append(toIndentedString(countryCode)).append("\n");
        sb.append("    streams: ").append(toIndentedString(streams)).append("\n");
        sb.append("    artistId: ").append(toIndentedString(artistId)).append("\n");
        sb.append("    trackId: ").append(toIndentedString(trackId)).append("\n");
        sb.append("    playlistId: ").append(toIndentedString(playlistId)).append("\n");
        sb.append("    isrc: ").append(toIndentedString(isrc)).append("\n");
        sb.append("    appleAgeBands: ").append(toIndentedString(appleAgeBands)).append("\n");
        sb.append("    spotifyAgeBands: ").append(toIndentedString(spotifyAgeBands)).append("\n");
        sb.append("    genders: ").append(toIndentedString(genders)).append("\n");
        sb.append("    hasStationStreams: ").append(toIndentedString(hasStationStreams)).append("\n");
        sb.append("}");
        return sb.toString();
    }

    /**
     * Convert the given object to string with each line indented by 4 spaces (except the first line).
     */
    private String toIndentedString(Object o) {
        if (o == null) {
            return "null";
        }
        return o.toString().replace("\n", "\n    ");
    }
}
