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 org.springframework.format.annotation.DateTimeFormat;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;

import io.delphiplatform.api.util.model.ModelUtils;
import io.delphiplatform.api.v3.model.gras.ProductVersion;
import io.delphiplatform.api.v3.model.service.ImageService;
import io.delphiplatform.api.v3.rdb.entity.ProductEntity;
import lombok.Data;

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

    @JsonProperty("name")
    private String name;

    @JsonProperty("product_id")
    private String productId;

    @JsonProperty("config_key")
    private String configKey;

    @JsonProperty("is_explicit")
    private Boolean isExplicit;

    @JsonProperty("digital_title_suppl")
    private JsonNullable<String> digitalTitleSuppl = JsonNullable.undefined();

    @JsonProperty("product_version")
    private ProductVersion productVersion;

    @JsonProperty("sub_title")
    private JsonNullable<String> subTitle = JsonNullable.undefined();

    @JsonProperty("release_date")
    @DateTimeFormat(
        iso = DateTimeFormat.ISO.DATE)
    private JsonNullable<LocalDate> releaseDate = JsonNullable.undefined();

    @JsonProperty("artists")
    @Valid
    private List<ArtistSimple> artists = null;

    @JsonProperty("tracks")
    @Valid
    private List<TrackSimple> tracks = null;

    @JsonProperty("label")
    private Label label;

    public static Product from(ProductEntity product, ImageService imageService) {
        if (product == null) {
            return null;
        }
        return new Product()
            .name(product.getName())
            .productId(product.getProductId())
            .digitalTitleSuppl(product.getDigitalTitleSuppl())
            .productVersion(ProductVersion.from(product.getProductVersion()))
            .subTitle(product.getSubTitle())
            .isExplicit(product.getIsExplicit())
            .configKey(product.getConfiguration() == null ? null : product.getConfiguration().getConfigKey())
            .label(Label.from(product.getLabel()))
            .releaseDate(product.getReleaseDate())
            .artists(ModelUtils.map(product.getArtists(), a -> ArtistSimple.from(a, imageService)))
            .tracks(ModelUtils.map(product.getTracks(), TrackSimple::from));
    }

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


    public Product isExplicit(Boolean isExplicit) {
        this.isExplicit = isExplicit;
        return this;
    }

    public Product productId(String productId) {
        this.productId = productId;
        return this;
    }

    public Product configKey(String configKey) {
        this.configKey = configKey;
        return this;
    }

    public Product digitalTitleSuppl(String digitalTitleSuppl) {
        this.digitalTitleSuppl = JsonNullable.of(digitalTitleSuppl);
        return this;
    }

    public Product productVersion(ProductVersion productVersion) {
        this.productVersion = productVersion;
        return this;
    }

    public Product subTitle(String subTitle) {
        this.subTitle = JsonNullable.of(subTitle);
        return this;
    }

    public Product releaseDate(LocalDate releaseDate) {
        this.releaseDate = JsonNullable.of(releaseDate);
        return this;
    }

    public Product artists(List<ArtistSimple> artists) {
        this.artists = artists;
        return this;
    }

    public Product addArtistsItem(ArtistSimple artistsItem) {
        if (this.artists == null) {
            this.artists = new ArrayList<>();
        }
        this.artists.add(artistsItem);
        return this;
    }

    public Product tracks(List<TrackSimple> tracks) {
        this.tracks = tracks;
        return this;
    }

    public Product addTracksItem(TrackSimple tracksItem) {
        if (this.tracks == null) {
            this.tracks = new ArrayList<>();
        }
        this.tracks.add(tracksItem);
        return this;
    }

    public Product label(Label label) {
        this.label = label;
        return this;
    }

}
