package main

import (
	"os"
	"fmt"
	"io/ioutil"
	"net/http"
	"path/filepath"
	"regexp"
	"strconv"
)

const (
	VALID_ID_REGEX = `^[0-9]+$`
)

type Recipe struct {
	Id	string
	Title	string
	Text	string
	Html	string
}

func indexGet(w http.ResponseWriter, r *http.Request) {

	entries, err := os.ReadDir(filepath.Join(config.Data, "recipes"))
	if err != nil {
		http.Error(w, "Could not list recipes!", 500)
		return
	}

	recipes := make([]Recipe, 0)

	for _,v := range entries {
		if v.IsDir() == false {
			continue
		}

		_, err = strconv.Atoi(v.Name())
		if err != nil {
			continue
		}

		textpath := filepath.Join(config.Data, "recipes", v.Name(), "text")
		data, _ := ioutil.ReadFile(textpath)
		markup := Markup(data)

		recipes = append(recipes, Recipe{
			v.Name(),
			markup.title(),
			string(data),
			"",
		})
	}

	ServeTemplate(w, "index.html", recipes)
}

func recipeGet(w http.ResponseWriter, r *http.Request) {

	ids := r.URL.Query()["id"]
	if len(ids) != 1 {
		msg := fmt.Sprintf("Exactly 1 'id' URL parameter expected but %d provided.", len(ids))
		http.Error(w, msg, 400)
		return
	}
	idStr := ids[0]

	textpath := filepath.Join(config.Data, "recipes", idStr, "text")
	data, _ := ioutil.ReadFile(textpath)
	markup := Markup(data)

	recipe := Recipe{
		idStr,
		markup.title(),
		string(data),
		markup.html(),
	}

	ServeTemplate(w, "recipe.html", recipe)
}

func recipeEditGet(w http.ResponseWriter, r *http.Request) {

	ids := r.URL.Query()["id"]
	if len(ids) != 1 {
		msg := fmt.Sprintf("Exactly 1 'id' URL parameter expected but %d provided.", len(ids))
		http.Error(w, msg, 400)
		return
	}
	idStr := ids[0]

	textpath := filepath.Join(config.Data, "recipes", idStr, "text")
	data, _ := ioutil.ReadFile(textpath)

	recipe := Recipe{
		idStr,
		"",
		string(data),
		"",
	}

	ServeTemplate(w, "recipe_edit.html", recipe)
}

func recipeEditPost(w http.ResponseWriter, r *http.Request) {

	ids := r.URL.Query()["id"]
	if len(ids) != 1 {
		http.Error(w, "Exactly 1 'id' URL parameter expected.", 400)
		return
	}
	idStr := ids[0]

	idRegex := regexp.MustCompile(VALID_ID_REGEX)
	if !(idRegex.MatchString(idStr)) {
		http.Error(w, "Bad 'id' URL parameter.", 400)
		return
	}

	buffer, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Could not read request body.", 400)
		return
	}

	textpath := filepath.Join(config.Data, "recipes", idStr, "text")
	err = ioutil.WriteFile(textpath, buffer, 0644)
	if err != nil {
		http.Error(w, "Could not save new text for recipe.", 500)
	}
}

func recipeConfirmDeletionGet(w http.ResponseWriter, r *http.Request) {

	ids := r.URL.Query()["id"]
	if len(ids) != 1 {
		http.Error(w, "Exactly 1 'id' URL parameter expected.", 400)
		return
	}

	recipe := Recipe{ids[0], "", "", ""}

	ServeTemplate(w, "recipe_confirm_deletion.html", recipe)
}

func recipeConfirmDeletionPost(w http.ResponseWriter, r *http.Request) {

	ids := r.URL.Query()["id"]
	if len(ids) != 1 {
		http.Error(w, "Exactly 1 'id' URL parameter expected.", 400)
		return
	}

	recipedir := filepath.Join(config.Data, "recipes", ids[0])
	err := os.RemoveAll(recipedir)
	if err != nil {
		http.Error(w, "Could not delete recipe.", 500)
		return;
	}

	http.Redirect(w, r, "/index.html", 303)
}

func addRecipesGet(w http.ResponseWriter, r *http.Request) {

	entries, err := os.ReadDir(filepath.Join(config.Data, "recipes"))
	if err != nil {
		http.Error(w, "Could not get list of existing recipes!", 500)
		return
	}

	var biggest int = -1

	for _,v := range entries {
		if v.IsDir() == false {
			continue
		}

		number, err := strconv.Atoi(v.Name())
		if err != nil {
			continue
		}

		if number > biggest {
			biggest = number
		}
	}

	newId := biggest + 1
	newIdStr := strconv.Itoa(newId)

	recipedir := filepath.Join(config.Data, "recipes", newIdStr)
	err = os.Mkdir(recipedir, 0755)
	if err != nil {
		http.Error(w, "Could not create new recipe!", 500)
		return
	}

	textpath := filepath.Join(config.Data, "recipes", newIdStr, "text")
	err = os.WriteFile(textpath, make([]byte, 0), 0644)
	if err != nil {
		http.Error(w, "Could not create new recipe!", 500)
		return
	}

	redirect := fmt.Sprintf("/recipe/edit?id=%d", newId)
	http.Redirect(w, r, redirect, 303)
}

func staticGet(w http.ResponseWriter, r *http.Request, filename string) {

	path := filepath.Join(config.Static, filename)
	http.ServeFile(w, r, path)
}