package app.mealsmadeeasy.api.recipe;

import app.mealsmadeeasy.api.image.Image;
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
import app.mealsmadeeasy.api.user.User;
import io.hypersistence.utils.hibernate.type.json.JsonBinaryType;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.Type;
import org.jetbrains.annotations.Nullable;

import java.time.OffsetDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Entity
@Getter
@Setter
@ToString
public class Recipe {

    @Getter
    @Setter
    @ToString
    public static class Ingredient {

        @Nullable
        private String amount;

        private String name;

        @Nullable
        private String notes;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o instanceof Ingredient other) {
                return Objects.equals(this.amount, other.amount)
                        && Objects.equals(this.name, other.name)
                        && Objects.equals(this.notes, other.notes);
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return Objects.hash(this.amount, this.name, this.notes);
        }

    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(updatable = false)
    private Integer id;

    @Basic(optional = false)
    private OffsetDateTime created;

    private OffsetDateTime modified;

    @Basic(optional = false)
    @Column(unique = true)
    private String slug;

    @Basic(optional = false)
    private String title;

    @Nullable
    private Integer preparationTime;

    @Nullable
    private Integer cookingTime;

    @Nullable
    private Integer totalTime;

    @Type(JsonBinaryType.class)
    @Column(columnDefinition = "JSONB")
    @Nullable
    private List<Ingredient> ingredients;

    @Basic(optional = false)
    @Column(columnDefinition = "TEXT")
    private String rawText;

    @Column(columnDefinition = "TEXT")
    @Nullable
    private String cachedRenderedText;

    @ManyToOne(optional = false)
    @JoinColumn(name = "owner_id", nullable = false)
    private User owner;

    @OneToMany(mappedBy = "recipe", orphanRemoval = true, cascade = CascadeType.ALL)
    private Set<RecipeStar> stars = new HashSet<>();

    @OneToMany(mappedBy = "recipe", orphanRemoval = true, cascade = CascadeType.ALL)
    private Set<RecipeComment> comments = new HashSet<>();

    @Basic(optional = false)
    private Boolean isPublic = false;

    @ManyToMany
    @JoinTable(
            name = "recipe_viewer",
            joinColumns = @JoinColumn(name = "recipe_id"),
            inverseJoinColumns = @JoinColumn(name = "viewer_id")
    )
    private Set<User> viewers = new HashSet<>(); // todo: see if we can get rid of this init

    @ManyToOne
    @JoinColumn(name = "main_image_id")
    @Nullable
    private Image mainImage;

    @OneToOne(mappedBy = "recipe", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private RecipeSummary summary;

    @PrePersist
    private void prePersist() {
        this.created = OffsetDateTime.now();
    }

    @PreUpdate
    private void preUpdate() {
        this.modified = OffsetDateTime.now();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof Recipe other) {
            return Objects.equals(this.owner.getUsername(), other.owner.getUsername())
                    && Objects.equals(this.slug, other.slug);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.owner.getUsername(), this.slug);
    }

}
