package web

import (
	"errors"
	"net/http"
	"time"

	"party.at/party/cmd/party/common"
	"party.at/party/internal/data"
)

func (web *Web) Register(w http.ResponseWriter, r *http.Request) {
	web.render(w, r, http.StatusOK, "register", struct {
		AuthenticatedUser *data.User
		FormErrors        []string
	}{
		AuthenticatedUser: common.GetUser(r),
	})
}

func (web *Web) RegisterUserPage(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	var altName *string
	if s := r.PostFormValue("alt_name"); s != "" {
		altName = &s
	}

	dob, err := time.Parse("2006-01-02", r.PostFormValue("date_of_birth"))
	if err != nil {
		dob = time.Time{}
	}

	_, authToken, err := web.App.RegisterUser(common.RegisterUserInput{
		ProviderID:  1,
		Username:    r.PostFormValue("username"),
		Email:       r.PostFormValue("email"),
		Password:    r.PostFormValue("password"),
		Name:        r.PostFormValue("name"),
		AltName:     altName,
		DateOfBirth: dob,
		Country:     r.PostFormValue("country"),
		PhoneNumber: r.PostFormValue("phone_number"),
		Address:     r.PostFormValue("address"),
	})
	if err != nil {
		var formErrors []string
		var customErr *data.Error

		if errors.As(err, &customErr) && len(customErr.Details) > 0 {
			formErrors = customErr.DetailMessages()
		}

		web.render(w, r, http.StatusUnprocessableEntity, "register", struct {
			AuthenticatedUser *data.User
			FormErrors        []string
		}{
			AuthenticatedUser: common.GetUser(r),
			FormErrors:        formErrors,
		})
		return
	}

	setCookie(w, authToken.Plaintext, authToken.Expiry)
	http.Redirect(w, r, "/issues", http.StatusSeeOther)
}

func (web *Web) ProfilePage(w http.ResponseWriter, r *http.Request) {
	user := common.GetUser(r)
	if user.IsAnonymous() {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}

	fullUser, err := web.App.GetUser(user, user.ID)
	if err != nil {
		if errors.Is(err, data.ErrRecordNotFound) {
			http.NotFound(w, r)
		} else {
			web.App.LogError(r, err)
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		}
		return
	}

	web.render(w, r, http.StatusOK, "profile", struct {
		AuthenticatedUser *data.User
		User              *data.User
	}{
		AuthenticatedUser: user,
		User:              fullUser,
	})
}

func (web *Web) UsersPage(w http.ResponseWriter, r *http.Request) {
	user := common.GetUser(r)
	if user.IsAnonymous() {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}

	users, _, err := web.App.ListUsers(data.Filters{
		Page:         1,
		PageSize:     100,
		Sort:         "id",
		SortSafelist: []string{"id", "-id", "name", "-name"},
	})
	if err != nil {
		web.App.LogError(r, err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	permissions := common.GetPermissions(r)
	if !permissions.Include("users:read") {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}

	web.render(w, r, http.StatusOK, "users", struct {
		AuthenticatedUser *data.User
		Users             []*data.User
		CanManageUsers    bool
	}{
		AuthenticatedUser: user,
		Users:             users,
		CanManageUsers:    true,
	})
}

func (web *Web) ActivatePage(w http.ResponseWriter, r *http.Request) {
	web.render(w, r, http.StatusOK, "activated", struct {
		AuthenticatedUser *data.User
		FormErrors        []string
		Token             string
	}{
		AuthenticatedUser: common.GetUser(r),
		Token:             r.URL.Query().Get("token"),
	})
}

func (web *Web) ActivateUserAction(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	token := r.PostFormValue("token")
	_, err := web.App.ActivateUser(token)
	if err != nil {
		var msg string
		if errors.Is(err, data.ErrRecordNotFound) {
			msg = "Ungültiger oder abgelaufener Aktivierungstoken."
		} else {
			web.App.LogError(r, err)
			msg = "Aktivierung fehlgeschlagen. Bitte versuchen Sie es erneut."
		}
		web.render(w, r, http.StatusUnprocessableEntity, "activated", struct {
			AuthenticatedUser *data.User
			FormErrors        []string
			Token             string
		}{
			AuthenticatedUser: common.GetUser(r),
			FormErrors:        []string{msg},
			Token:             token,
		})
		return
	}

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

func (web *Web) DeleteUserAction(w http.ResponseWriter, r *http.Request) {
	currentUser := common.GetUser(r)
	if currentUser.IsAnonymous() {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	id, err := common.ReadIDParam(r)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	if err = web.App.DeleteUser(id); err != nil {
		if errors.Is(err, data.ErrRecordNotFound) {
			http.NotFound(w, r)
		} else {
			web.App.LogError(r, err)
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		}
		return
	}

	if currentUser.ID == id {
		clearCookie(w)
		w.Header().Set("HX-Redirect", "/")
	} else {
		w.Header().Set("HX-Redirect", "/users")
	}
	w.WriteHeader(http.StatusOK)
}
