package repository

import (
	"database/sql"
	"encoding/json"

	domain "github.com/haydenhargreaves/Potion/internal/domain/recipe"
	"github.com/lib/pq"
)

type RecipeRepository struct {
	db *sql.DB
}

// Compile-time check to ensure the RecipeRepository implements domain.RecipeRepository
var _ domain.RecipeRepository = (*RecipeRepository)(nil)

// NewRecipeRepository creates a user repository object which is used by the user service to access
// the database. Any recipe related database operations will take place in this repository.
func NewRecipeRepository(db *sql.DB) domain.RecipeRepository {
	return &RecipeRepository{db: db}
}

// NOTE: This function modified the provided recipe with the new values, such as id and time stamp
func (r *RecipeRepository) CreateRecipe(recipe *domain.Recipe) error {
	tx, err := r.db.Begin()
	if err != nil {
		tx.Rollback()
		return err
	}

	query := `INSERT INTO recipes (
			title, description, instructions, serves, difficulty,
			duration, category, ingredients, userid, modified, created
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11
		) RETURNING id;`

	// NOTE: Data steps
	// cast duration to JSON
	// cast ingredients to JSON
	// cast category to string
	// use nil for the modified time

	durationJSON, err := json.Marshal(recipe.Duration)
	if err != nil {
		return err
	}

	ingredientsJSON, err := json.Marshal(recipe.Ingredients)
	if err != nil {
		return err
	}

	var id int
	if err = tx.QueryRow(
		query,
		recipe.Title,
		recipe.Description,
		pq.Array(recipe.Instructions),
		recipe.Serves,
		recipe.Difficulty,
		durationJSON,
		string(recipe.Category),
		ingredientsJSON,
		recipe.UserId,
		nil,
		recipe.Created,
	).Scan(&id); err != nil {
		tx.Rollback()
		return err
	}

	if err := tx.Commit(); err != nil {
		tx.Rollback()
		return err
	}

	// Set the new ID
	recipe.Id = id

	return nil
}
