package com.example.demo.entity;

import jakarta.persistence.*;
import java.util.List;
import java.util.ArrayList;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.EqualsAndHashCode;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "recipes")
public class Recipe {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	@NotBlank(message = "Please provide a recipe title")
	private String title;

	@Column(columnDefinition = "TEXT")
	private String description;
	
	@NotNull(message = "Please Provide a prep time amount in mintutes") 
	@Positive(message = "This value cannot be negative")
	private Integer prepTimeMinutes;
	
	@NotNull(message = "Please Provide a cook time amount in mintutes") 
	@Positive(message = "This value cannot be negative")
	private Integer cookTimeMinutes;
	
	@NotNull(message = "Please Provide a serving amount") 
	@Positive(message = "This value cannot be negative")
	private Integer servings;
	
	private String status;
	
	@NotNull(message = "Please Provide a cost") 
	@Positive(message = "This value cannot be negative")
	private Integer cost;
	
	private LocalDateTime createdAt;
	private LocalDateTime updatedAt;
	
	@NotNull(message = "Recipe must be associated with a user")
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "user_id", nullable = false)
	@EqualsAndHashCode.Include
	private User user;

	// Recipe ingredients relationship
	@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
	@NotEmpty(message = "At least one ingredient is required") 
	//hopfully add consistent order
	@OrderBy("orderIndex ASC")
	private List<RecipeIngredient> recipeIngredients = new ArrayList<>();
	
	// Recipe Steps relationship
	@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
	//hopefully to add order
	@OrderBy("stepNumber ASC")
	private List<Step> steps = new ArrayList<>();

	// Recipe Images relationship
	@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
	private Set<Image> images = new HashSet<>();

	// Recipe Tag relationship and also junction table
	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "recipe_tags", joinColumns = { @JoinColumn(name = "recipe_id") }, inverseJoinColumns = {
			@JoinColumn(name = "tag_id") })
	private Set<Tag> tags = new HashSet<>();

	// User is the manager for this relationship
	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "FavRecipes")
	private Set<User> users = new HashSet<>();

	public Recipe() {
	}

	public Recipe(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes, Integer servings,
			User user, String status, Integer cost) {
		this.title = title;
		this.description = description;
		this.prepTimeMinutes = prepTimeMinutes;
		this.cookTimeMinutes = cookTimeMinutes;
		this.servings = servings;
		this.user = user;
		this.status = status;
		this.createdAt = LocalDateTime.now();
		this.updatedAt = LocalDateTime.now();
		this.cost = cost;
	}

	// Getters and setters
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Integer getPrepTimeMinutes() {
		return prepTimeMinutes;
	}

	public void setPrepTimeMinutes(Integer prepTimeMinutes) {
		this.prepTimeMinutes = prepTimeMinutes;
	}

	public Integer getCookTimeMinutes() {
		return cookTimeMinutes;
	}

	public void setCookTimeMinutes(Integer cookTimeMinutes) {
		this.cookTimeMinutes = cookTimeMinutes;
	}

	public Integer getServings() {
		return servings;
	}

	public void setServings(Integer servings) {
		this.servings = servings;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public LocalDateTime getCreatedAt() {
		return createdAt;
	}

	public void setCreatedAt(LocalDateTime createdAt) {
		this.createdAt = createdAt;
	}

	public LocalDateTime getUpdatedAt() {
		return updatedAt;
	}

	public void setUpdatedAt(LocalDateTime updatedAt) {
		this.updatedAt = updatedAt;
	}

	public List<RecipeIngredient> getRecipeIngredients(){
		return recipeIngredients;
	}

	public void setRecipeIngredients(List<RecipeIngredient> recipeIngredients) {
		this.recipeIngredients = recipeIngredients;
	}

	public List<Step> getSteps(){
		return steps;
	}

	public void setSteps(List<Step> steps) {
		this.steps = steps;
	}

	public Set<Image> getImages() {
		return images;
	}

	public void setImages(Set<Image> images) {
		this.images = images;
	}

	public Set<Tag> getTags() {
		return tags;
	}

	public void setTags(Set<Tag> tags) {
		this.tags = tags;
	}

	public Set<User> getUsers() {
		return users;
	}

	public void setUsers(Set<User> users) {
		this.users = users;
	}

	public Integer getCost() {
		return cost;
	}

	public void setCost(Integer cost) {
		this.cost = cost;
	}
}

