package io.delphiplatform.api.v3.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import org.openapitools.jackson.nullable.JsonNullable;

import java.net.URI;
import java.util.Objects;

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

import io.delphiplatform.api.util.CollectionUtils;
import io.delphiplatform.api.util.model.ModelUtils;
import io.delphiplatform.api.v3.constant.CountryCodeConstant;
import io.delphiplatform.api.v3.constant.DspConstants;
import io.delphiplatform.api.v3.model.service.ImageService;
import io.delphiplatform.api.v3.rdb.entity.PlaylistEntity;
import io.delphiplatform.api.v3.rdb.entity.PlaylistProjection;

/**
 * Playlist
 */
@JsonPropertyOrder(alphabetic = true)
public class Playlist {

    @JsonProperty("name")
    private String name;

    @JsonProperty("playlist_id")
    private String playlistId;

    @JsonProperty("playlist_type")
    private String playlistType;

    @JsonProperty("uri")
    private JsonNullable<URI> uri = JsonNullable.undefined();

    @JsonProperty("num_tracks")
    private JsonNullable<Integer> numTracks = JsonNullable.undefined();

    @JsonProperty("country_code")
    private JsonNullable<String> countryCode = JsonNullable.undefined();

    @JsonProperty("rank")
    private JsonNullable<Integer> rank = JsonNullable.undefined();

    @JsonProperty("dsp")
    private Dsp dsp;

    @JsonProperty("dsp_playlist_id")
    private String dspPlaylistId;

    @JsonProperty("amazon_playlist_id")
    private String amazonPlaylistId;

    @JsonProperty("image")
    private JsonNullable<ImageSimple> image = JsonNullable.undefined();

    public static Playlist from(PlaylistEntity playlist, ImageService imageService) {
        if (playlist == null) {
            return null;
        }
        return new Playlist()
            .countryCode(playlist.getCountryCode())
            .dsp(Dsp.from(playlist.getDsp()))
            .dspPlaylistId(playlist.getDspPlaylistId())
            .name(playlist.getName())
            .numTracks(playlist.getNumTracks())
            .playlistId(playlist.getPlaylistId())
            .playlistType(CollectionUtils.isEmpty(playlist.getPlaylistType()) ? null : playlist.getPlaylistType())
            .rank(playlist.getRank())
            .image(imageService.resolveImage(playlist))
            .uri(ModelUtils.createUri(playlist.getUri()));
    }

    public static Playlist from(PlaylistProjection playlist, ImageService imageService) {
        if (playlist == null) {
            return null;
        }
        return new Playlist()
            .countryCode(playlist.getCountryCodeValue())
            .dsp(new Dsp()
                .dspId(playlist.getDspId())
                .name(playlist.getDspName())
                .slug(playlist.getDspSlug()))
            .dspPlaylistId(playlist.getDspPlaylistId())
            .name(playlist.getName())
            .numTracks(playlist.getNumTracks())
            .playlistId(playlist.getPlaylistId())
            .playlistType(CollectionUtils.isEmpty(playlist.getPlaylistType()) ? null : playlist.getPlaylistType())
            .rank(playlist.getRank())
            .image(imageService.resolveImage(playlist.getDspId(), playlist.getDspPlaylistId(), null, playlist.getArtworkUrl()))
            .uri(ModelUtils.createUri(playlist.getUri()));
    }

    public Playlist name(String name) {
        this.name = name;
        return this;
    }

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

    public void setName(String name) {
        this.name = name;
    }

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

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

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

    public Playlist uri(URI uri) {
        this.uri = JsonNullable.of(uri);
        return this;
    }

    public Playlist playlistType(String playlistType) {
        this.playlistType = playlistType;
        return this;
    }

    @NotNull
    public String getPlaylistType() {
        return playlistType;
    }

    public void setPlaylistType(String playlistType) {
        this.playlistType = playlistType;
    }

    /**
     * DSP URI to the playlist
     *
     * @return uri
     */
    @Valid
    public JsonNullable<URI> getUri() {
        return uri;
    }

    public void setUri(JsonNullable<URI> uri) {
        this.uri = uri;
    }

    public Playlist numTracks(Integer numTracks) {
        this.numTracks = JsonNullable.of(numTracks);
        return this;
    }

    /**
     * Total number of tracks in the playlist
     *
     * @return numTracks
     */
    public JsonNullable<Integer> getNumTracks() {
        return numTracks;
    }

    public void setNumTracks(JsonNullable<Integer> numTracks) {
        this.numTracks = numTracks;
    }

    public Playlist countryCode(String countryCode) {
        this.countryCode = JsonNullable.of(countryCode);
        return this;
    }

    /**
     * Typically a lower-case two letter code for the country
     *
     * @return countryCode
     */
    public JsonNullable<String> getCountryCode() {
        if ((countryCode == null || !countryCode.isPresent() || countryCode.get() == null)
            && dsp != null && DspConstants.APPLE.equals(dsp.getDspId())) {
            //Apple playlist w/o known country code is considered US. Source: DAE-7863
            return JsonNullable.of(CountryCodeConstant.US);
        }
        return countryCode;
    }

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

    public Playlist rank(Integer rank) {
        this.rank = JsonNullable.of(rank);
        return this;
    }

    /**
     * SME internal ranking latest for global region
     *
     * @return rank
     */
    public JsonNullable<Integer> getRank() {
        return rank;
    }

    public void setRank(JsonNullable<Integer> rank) {
        this.rank = rank;
    }

    public Playlist dsp(Dsp dsp) {
        this.dsp = dsp;
        return this;
    }

    /**
     * Get dsp
     *
     * @return dsp
     */
    @Valid
    public Dsp getDsp() {
        return dsp;
    }

    public void setDsp(Dsp dsp) {
        this.dsp = dsp;
    }

    public Playlist dspPlaylistId(String dspPlaylistId) {
        this.dspPlaylistId = dspPlaylistId;
        return this;
    }

    /**
     * Playlist object identifier used by the related Dsp.
     *
     * @return dspPlaylistId
     */
    public String getDspPlaylistId() {
        return dspPlaylistId;
    }

    public void setDspPlaylistId(String dspPlaylistId) {
        this.dspPlaylistId = dspPlaylistId;
    }

    public Playlist amazonPlaylistId(String amazonPlaylistId) {
        this.amazonPlaylistId = amazonPlaylistId;
        return this;
    }

    /**
     * Playlist object identifier used by Amazon (may not be available).
     *
     * @return amazonPlaylistId
     */
    public String getAmazonPlaylistId() {
        return amazonPlaylistId;
    }

    public void setAmazonPlaylistId(String amazonPlaylistId) {
        this.amazonPlaylistId = amazonPlaylistId;
    }

    public Playlist image(ImageSimple image) {
        this.image = JsonNullable.of(image);
        return this;
    }

    /**
     * Get image
     *
     * @return image
     */
    @Valid
    public JsonNullable<ImageSimple> getImage() {
        return image;
    }

    public void setImage(JsonNullable<ImageSimple> image) {
        this.image = image;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Playlist playlist = (Playlist) o;
        return Objects.equals(this.name, playlist.name) &&
            Objects.equals(this.playlistId, playlist.playlistId) &&
            Objects.equals(this.uri, playlist.uri) &&
            Objects.equals(this.numTracks, playlist.numTracks) &&
            Objects.equals(this.countryCode, playlist.countryCode) &&
            Objects.equals(this.rank, playlist.rank) &&
            Objects.equals(this.dsp, playlist.dsp) &&
            Objects.equals(this.dspPlaylistId, playlist.dspPlaylistId) &&
            Objects.equals(this.amazonPlaylistId, playlist.amazonPlaylistId) &&
            Objects.equals(this.image, playlist.image);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, playlistId, uri, numTracks, countryCode, rank, dsp, dspPlaylistId, amazonPlaylistId, image);
    }

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

        sb.append("    name: ").append(toIndentedString(name)).append("\n");
        sb.append("    playlistId: ").append(toIndentedString(playlistId)).append("\n");
        sb.append("    uri: ").append(toIndentedString(uri)).append("\n");
        sb.append("    numTracks: ").append(toIndentedString(numTracks)).append("\n");
        sb.append("    countryCode: ").append(toIndentedString(countryCode)).append("\n");
        sb.append("    rank: ").append(toIndentedString(rank)).append("\n");
        sb.append("    dsp: ").append(toIndentedString(dsp)).append("\n");
        sb.append("    dspPlaylistId: ").append(toIndentedString(dspPlaylistId)).append("\n");
        sb.append("    amazonPlaylistId: ").append(toIndentedString(amazonPlaylistId)).append("\n");
        sb.append("    image: ").append(toIndentedString(image)).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    ");
    }
}
