package main

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"

	"brainminder.speedtech.it/internal/request"
	"brainminder.speedtech.it/internal/response"
	"brainminder.speedtech.it/internal/validator"
	"brainminder.speedtech.it/models"
	"github.com/alexedwards/flow"
)

type categoryForm struct {
	Id        int64               `form:"Id"`
	Name      string              `form:"Name"`
	Validator validator.Validator `form:"-"`
}

func (form *categoryForm) Validate(w http.ResponseWriter, r *http.Request, app *application, data map[string]any) bool {
	var fullBuf = new(bytes.Buffer)

	form.Validator.CheckField(form.Name != "", "Name", "Name is required")

	if form.Validator.HasErrors() {
		w.Header().Add("HX-Retarget", "#message")
		w.Header().Add("HX-Trigger-After-Settle", `{"showMessage":""}`)

		data["messageType"] = "failure"
		data["messageContent"] = "Impossible to save the type"
		data["messageFieldErrors"] = form.Validator.FieldErrors

		buf, err := response.Fragment([]string{"partials/message.tmpl"}, "message", data)
		if err != nil {
			app.serverError(w, r, err)
		}
		fullBuf.Write(buf.Bytes())

		if err != nil {
			app.serverError(w, r, err)
		}
		_, err = fullBuf.WriteTo(w)
		if err != nil {
			app.logError("Building category form buffer : ", err)
		}

		w.WriteHeader(http.StatusUnprocessableEntity)
		return false
	}

	return true
}

func (app *application) categories(w http.ResponseWriter, r *http.Request) {
	data := app.newTemplateData(r)

	categoryModel := &models.CategoryModel{DB: app.db}
	rows, _, _ := categoryModel.All()

	data["categories"] = &rows
	data["messageType"] = ""
	data["messageContent"] = ""

	if r.Header.Get("HX-Request") == "true" {
		var fullBuf = new(bytes.Buffer)

		err := response.HXFragment(fullBuf, []string{"categories/list.tmpl"}, "categories:list", data)
		if err != nil {
			app.serverError(w, r, err)
		}

		err = response.HXFragmentOOB(fullBuf, []string{"categories/list_title.tmpl"}, "page:title", data, "page-title")
		if err != nil {
			app.serverError(w, r, err)
		}

		_, err = fullBuf.WriteTo(w)
		if err != nil {
			app.logError("Building categories list buffer : ", err)
		}
	} else {
		err := response.Page(w, http.StatusOK, data, []string{"categories/index.tmpl", "categories/list.tmpl", "categories/list_title.tmpl"})
		if err != nil {
			app.serverError(w, r, err)
		}
	}

	w.WriteHeader(http.StatusOK)
}

func (app *application) categoryCreate(w http.ResponseWriter, r *http.Request) {
	categoryModel := &models.CategoryModel{DB: app.db}
	var fullBuf = new(bytes.Buffer)
	var categoryId int64

	data := app.newTemplateData(r)
	data["formAction"] = "/category/create"
	data["formTarget"] = "#page-content"
	data["messageType"] = ""
	data["messageContent"] = ""

	switch r.Method {
	case http.MethodGet:

		data["category"] = categoryForm{
			Name: "",
		}

		if r.Header.Get("HX-Request") == "true" {
			err := response.HXFragment(fullBuf, []string{"categories/form.tmpl"}, "page:content", data)
			if err != nil {
				app.serverError(w, r, err)
			}

			err = response.HXFragmentOOB(fullBuf, []string{"categories/create_title.tmpl"}, "page:title", data, "page-title")
			if err != nil {
				app.serverError(w, r, err)
			}

			_, err = fullBuf.WriteTo(w)
			if err != nil {
				app.logError("Building category create form buffer : ", err)
			}
		} else {
			err := response.Page(w, http.StatusOK, data, []string{"categories/create_title.tmpl", "categories/form.tmpl"})
			if err != nil {
				app.serverError(w, r, err)
			}
		}

	case http.MethodPost:
		var categoryFromForm categoryForm

		err := request.DecodePostForm(r, &categoryFromForm)
		if err != nil {
			app.serverError(w, r, err)
		}

		if !categoryFromForm.Validate(w, r, app, data) {
			return
		}

		category := &models.Category{
			Name: categoryFromForm.Name,
		}

		categoryId, err = categoryModel.Create(category)
		if err != nil {
			app.badRequest(w, err)
			return
		}

		data["formAction"] = fmt.Sprint("/category/update/", categoryId)
		data["formTarget"] = "#page-content"

		data["category"] = categoryForm{
			Id:   categoryId,
			Name: category.Name,
		}

		err = response.HXFragment(fullBuf, []string{"categories/form.tmpl"}, "page:content", data)
		if err != nil {
			app.serverError(w, r, err)
		}

		err = response.HXFragmentOOB(fullBuf, []string{"categories/update_title.tmpl"}, "page:title", data, "page-title")
		if err != nil {
			app.serverError(w, r, err)
		}

		dataMessage := make(map[string]string)
		dataMessage["messageType"] = "success"
		dataMessage["messageContent"] = "Category created successfully"
		err = response.HXFragmentOOB(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage, "message")
		if err != nil {
			app.serverError(w, r, err)
		}

		w.Header().Add("HX-Trigger-After-Settle", `{"showMessage":""}`)
		w.Header().Add("HX-Replace-Url", fmt.Sprint("/type/update/", categoryId))
		_, err = fullBuf.WriteTo(w)
		if err != nil {
			app.logError("Building category update form buffer after post on create : ", err)
		}

		w.WriteHeader(http.StatusUnprocessableEntity)
	}
}

func (app *application) categoryUpdate(w http.ResponseWriter, r *http.Request) {
	categoryModel := &models.CategoryModel{DB: app.db}
	categoryIdStr := flow.Param(r.Context(), "category_id")
	categoryId, _ := strconv.Atoi(categoryIdStr)
	category, _, _ := categoryModel.One(categoryId)

	data := app.newTemplateData(r)
	data["formAction"] = "/category/update/" + categoryIdStr
	data["formTarget"] = "#message"
	data["messageType"] = ""
	data["messageContent"] = ""

	var fullBuf = new(bytes.Buffer)

	switch r.Method {
	case http.MethodGet:

		data["category"] = categoryForm{
			Id:   category.Id,
			Name: category.Name,
		}

		if r.Header.Get("HX-Request") == "true" {

			err := response.HXFragment(fullBuf, []string{"categories/form.tmpl"}, "page:content", data)
			if err != nil {
				app.serverError(w, r, err)
			}

			err = response.HXFragmentOOB(fullBuf, []string{"categories/update_title.tmpl"}, "page:title", data, "page-title")
			if err != nil {
				app.serverError(w, r, err)
			}

			_, err = fullBuf.WriteTo(w)
			if err != nil {
				app.logError("Building category update form buffer : ", err)
			}
		} else {
			err := response.Page(w, http.StatusOK, data, []string{"categories/update_title.tmpl", "categories/form.tmpl"})
			if err != nil {
				app.serverError(w, r, err)
			}
		}

	case http.MethodPost:
		var categoryFromForm categoryForm

		err := request.DecodePostForm(r, &categoryFromForm)
		if err != nil {
			app.serverError(w, r, err)
		}

		if !categoryFromForm.Validate(w, r, app, data) {
			return
		}

		category.Name = categoryFromForm.Name

		err = categoryModel.Update(category)
		if err != nil {
			app.badRequest(w, err)
			return
		}

		data["category"] = categoryForm{
			Id:   category.Id,
			Name: category.Name,
		}

		dataMessage := make(map[string]string)
		dataMessage["messageType"] = "success"
		dataMessage["messageContent"] = "Category saved successfully"
		err = response.HXFragment(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage)
		if err != nil {
			app.serverError(w, r, err)
		}

		err = response.HXFragmentOOB(fullBuf, []string{"categories/update_title.tmpl"}, "page:title", data, "page-title")
		if err != nil {
			app.serverError(w, r, err)
		}

		w.Header().Add("HX-Trigger-After-Settle", `{"showMessage":""}`)
		_, err = fullBuf.WriteTo(w)
		if err != nil {
			app.logError("Building category update form buffer after post on update : ", err)
		}
		w.WriteHeader(http.StatusUnprocessableEntity)
	}
}

func (app *application) categoryDelete(w http.ResponseWriter, r *http.Request) {
	categoryModel := &models.CategoryModel{DB: app.db}
	categoryIdStr := flow.Param(r.Context(), "category_id")
	categoryId, _ := strconv.Atoi(categoryIdStr)

	_, err := categoryModel.Delete(categoryId)
	if err != nil {
		app.serverError(w, r, err)
	}
}
