package handlers

import (
	"errors"
	"net/http"
	"strings"

	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgconn"
	"github.com/jackc/pgx/v5/pgtype"

	"wherewoof/frontend/internal/auth"
	"wherewoof/frontend/internal/db"
)

func (a *App) RegisterPage(w http.ResponseWriter, r *http.Request) {
	a.render(w, r, "register", "Create account", nil, "")
}

func (a *App) Register(w http.ResponseWriter, r *http.Request) {
	email := strings.ToLower(strings.TrimSpace(r.FormValue("email")))
	password := r.FormValue("password")
	name := strings.TrimSpace(r.FormValue("name"))

	if email == "" || password == "" {
		a.render(w, r, "register", "Create account", nil, "Email and password are required.")
		return
	}
	if len(password) < 8 {
		a.render(w, r, "register", "Create account", nil, "Password must be at least 8 characters.")
		return
	}
	if len([]byte(password)) > 72 {
		a.render(w, r, "register", "Create account", nil, "Password must be 72 bytes or fewer.")
		return
	}

	hash, err := auth.HashPassword(password)
	if err != nil {
		http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}

	user, err := a.Queries.CreateUser(r.Context(), db.CreateUserParams{
		Email:        email,
		PasswordHash: hash,
		Name:         pgtype.Text{String: name, Valid: name != ""},
	})
	if err != nil {
		var pgErr *pgconn.PgError
		if errors.As(err, &pgErr) && pgErr.Code == "23505" {
			a.render(w, r, "register", "Create account", nil, "That email is already registered.")
			return
		}
		http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}

	if err := auth.SetUserID(w, r, user.ID); err != nil {
		http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/account", http.StatusSeeOther)
}

func (a *App) LoginPage(w http.ResponseWriter, r *http.Request) {
	a.render(w, r, "login", "Log in", nil, "")
}

func (a *App) Login(w http.ResponseWriter, r *http.Request) {
	email := strings.ToLower(strings.TrimSpace(r.FormValue("email")))
	password := r.FormValue("password")

	user, err := a.Queries.GetUserByEmail(r.Context(), email)
	if err != nil {
		if !errors.Is(err, pgx.ErrNoRows) {
			http.Error(w, "internal error", http.StatusInternalServerError)
			return
		}
		a.render(w, r, "login", "Log in", nil, "Invalid email or password.")
		return
	}
	if !auth.CheckPassword(user.PasswordHash, password) {
		a.render(w, r, "login", "Log in", nil, "Invalid email or password.")
		return
	}

	if err := auth.SetUserID(w, r, user.ID); err != nil {
		http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/account", http.StatusSeeOther)
}

func (a *App) Logout(w http.ResponseWriter, r *http.Request) {
	_ = auth.Clear(w, r)
	http.Redirect(w, r, "/", http.StatusSeeOther)
}
