package domain

import "time"

// RecipeDuration is the duration to prepare recipe. It has JSON tags which allows it to be
// marshaled into a JSON object and stored in the database (JSONB).
type RecipeDuration struct {
	Total int `json:"Total"`
	Prep  int `json:"Prep"`
	Cook  int `json:"Cook"`
}

// RecipeMeal is the database enum E_MEAL which defines the meal type of a recipe. Postgres enums
// are case sensitive so these must match the values in the database exactly.
type RecipeMeal string

const (
	MealBreakfast RecipeMeal = "breakfast"
	MealLunch     RecipeMeal = "lunch"
	MealDinner    RecipeMeal = "dinner"
	MealDesert    RecipeMeal = "dessert"
	MealSnack     RecipeMeal = "snack"
	MealSide      RecipeMeal = "side"
	MealOther     RecipeMeal = "other"
)

// ParseMeal converts an integer value into a meal type (string). Values are 0-indexed.
func ParseMeal(meal int) RecipeMeal {
	switch meal {
	case 0:
		return MealBreakfast
	case 1:
		return MealLunch
	case 2:
		return MealDinner
	case 3:
		return MealDesert
	case 4:
		return MealSnack
	case 5:
		return MealSide
	case 6:
		return MealOther
	default:
		return MealOther
	}
}

// TODO: Comment
type RecipeIngredientUnit string

const (
	Blank    RecipeIngredientUnit = ""
	Tsp      RecipeIngredientUnit = "tsp"
	Tbsp     RecipeIngredientUnit = "tbsp"
	FlOz     RecipeIngredientUnit = "fl oz"
	Cup      RecipeIngredientUnit = "cup"
	Ml       RecipeIngredientUnit = "ml"
	Litre    RecipeIngredientUnit = "l"
	Pint     RecipeIngredientUnit = "pt"
	Quart    RecipeIngredientUnit = "qt"
	Gallon   RecipeIngredientUnit = "gal"
	Gram     RecipeIngredientUnit = "g"
	Kilogram RecipeIngredientUnit = "kg"
	Ounce    RecipeIngredientUnit = "oz"
	Pound    RecipeIngredientUnit = "lb"
	Piece    RecipeIngredientUnit = "piece"
	Clove    RecipeIngredientUnit = "clove"
	Slice    RecipeIngredientUnit = "slice"
	Stick    RecipeIngredientUnit = "stick"
	Bunch    RecipeIngredientUnit = "bunch"
	Pinch    RecipeIngredientUnit = "pinch"
	Dash     RecipeIngredientUnit = "dash"
	Splash   RecipeIngredientUnit = "splash"
	ToTaste  RecipeIngredientUnit = "to taste"
)

// RecipeIngredient is a single ingredients in a recipe. These have JSON tags which allow them
// to be marshaled into a JSON array and stored in the database (JSONB).
type RecipeIngredient struct {
	Id        string               `json:"Id"`
	SectionId string               `json:"SectionId"`
	Name      string               `json:"Name"`
	Amount    float64              `json:"Amount"`
	Unit      RecipeIngredientUnit `json:"Unit"`
}

// TODO: Comment
type RecipeInstruction struct {
	Id      string `json:"Id"`
	Content string `json:"Content"`
}

// TODO: Comment
type RecipeIngredientSection struct {
	Id   string `json:"Id"`
	Name string `json:"Name"`
}

// RecipeIngredientStore is the struct stored in the database Ingredients column. It is simply a
// combindation of the sections and the ingredients so they can be stored together.
type RecipeIngredientStore struct {
	Sections    []RecipeIngredientSection `json:"Sections"`
	Ingredients []RecipeIngredient        `json:"Ingredients"`
}

// Recipe is the database model of a recipe. There is no need to map to a different model so
// this will remain in the domain. The Tags field should be loaded from the external Tags table,
// but is still attached to this domain object. The Favorite field should also be loaded from
// the external favorites table, these are user specific.
type Recipe struct {
	Id           int
	Title        string
	Description  string
	Instructions []RecipeInstruction
	Serves       int
	Difficulty   int
	Duration     RecipeDuration
	Category     RecipeMeal
	Ingredients  []RecipeIngredient
	Sections     []RecipeIngredientSection
	UserId       int
	Modified     *time.Time // Pointer to allow null
	Created      time.Time
	Tags         []Tag
	Favorite     bool // Per requesting user
	Deleted      bool
}

// SearchFilters is a model which represents the required filters to complete a recipe search.
// The integer values should be provided as bits and used to parse out individual flags. More
// details can be found in the SearchRecipes service function.
type SearchFilters struct {
	Search      string `json:"Search"`
	MealType    int    `json:"MealType"`
	Time        int    `json:"Time"`
	Difficulty  int    `json:"Difficulty"`
	ServingSize int    `json:"ServingSize"`
	Favorites   bool   `json:"Favorites"`
}

// Tag is a model which represents a single tag in the Tags table. A tag is mapped to a recipe
// using the RecipeTag data model and can be accessed via their ID from the DB.
type Tag struct {
	Id      int
	Name    string
	Created time.Time
}

// RecipeTag is a model which represents a single mapping in the RecipeTags table. This model
// is a many-to-many mapping for tags to recipes.
type RecipeTag struct {
	Id       int
	RecipeId int
	TagId    int
	Created  time.Time
}

// TODO: Document
type CreateRecipeRequest struct {
	Title        string
	Description  string
	Instructions []RecipeInstruction
	Serves       int
	Difficulty   int
	Duration     RecipeDuration
	Category     RecipeMeal
	Ingredients  []RecipeIngredient
	Sections     []RecipeIngredientSection
	Tags         []string
}

// TODO Document
type EditRecipeRequest struct {
	Id           int
	Title        string
	Description  string
	Instructions []RecipeInstruction
	Serves       int
	Difficulty   int
	Duration     RecipeDuration
	Category     RecipeMeal
	Ingredients  []RecipeIngredient
	Sections     []RecipeIngredientSection
	Tags         []string
}
