package handlers

import (
	"html"
	"net/http"
	"net/url"
	"strings"

	"leadb2b.org/internal/auth"
)

type AuthHandler struct {
	auth *auth.Service
}

func NewAuthHandler(authSvc *auth.Service) *AuthHandler {
	return &AuthHandler{auth: authSvc}
}

func (h *AuthHandler) ShowLogin(w http.ResponseWriter, r *http.Request) {
	if h.auth.TokenFromRequest(r) != "" {
		if sess, err := h.auth.ResolveSession(r.Context(), h.auth.TokenFromRequest(r)); err == nil && sess != nil {
			http.Redirect(w, r, "/app", http.StatusFound)
			return
		}
	}
	h.renderAuth(w, AuthPageData{
		Mode:        "login",
		Title:       "Entrar",
		Next:        r.URL.Query().Get("next"),
		Error:       r.URL.Query().Get("error"),
		ErrorMsg:    r.URL.Query().Get("msg"),
		FormAction:  "/login",
		AltLink:     "/cadastro",
		AltLinkText: "Criar conta grátis",
	})
}

func (h *AuthHandler) ShowRegister(w http.ResponseWriter, r *http.Request) {
	h.renderAuth(w, AuthPageData{
		Mode:        "register",
		Title:       "Criar conta",
		FormAction:  "/cadastro",
		AltLink:     "/login",
		AltLinkText: "Já tenho conta",
		Error:       r.URL.Query().Get("error"),
		ErrorMsg:    r.URL.Query().Get("msg"),
	})
}

func (h *AuthHandler) ShowForgotPassword(w http.ResponseWriter, r *http.Request) {
	h.renderAuth(w, AuthPageData{
		Mode:        "forgot",
		Title:       "Recuperar senha",
		FormAction:  "/recuperar-senha",
		AltLink:     "/login",
		AltLinkText: "Voltar ao login",
		Error:       r.URL.Query().Get("error"),
		OK:          r.URL.Query().Get("ok"),
	})
}

func (h *AuthHandler) ShowResetPassword(w http.ResponseWriter, r *http.Request) {
	h.renderAuth(w, AuthPageData{
		Mode:        "reset",
		Title:       "Nova senha",
		FormAction:  "/redefinir-senha",
		AltLink:     "/login",
		AltLinkText: "Ir para login",
		Error:       r.URL.Query().Get("error"),
		ErrorMsg:    r.URL.Query().Get("msg"),
		Token:       r.URL.Query().Get("token"),
	})
}

func (h *AuthHandler) PostLogin(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Redirect(w, r, "/login?error=invalid", http.StatusFound)
		return
	}
	email := strings.TrimSpace(r.FormValue("email"))
	password := r.FormValue("password")
	sess, err := h.auth.Login(r.Context(), email, password)
	if err != nil {
		q := url.Values{"error": {"credentials"}}
		if msg := loginErrorMessage(err); msg != "" {
			q.Set("msg", msg)
		}
		http.Redirect(w, r, "/login?"+q.Encode(), http.StatusFound)
		return
	}
	h.auth.SetTokenCookie(w, sess.Token)
	next := r.FormValue("next")
	if next == "" {
		next = "/app/busca"
	}
	http.Redirect(w, r, next, http.StatusFound)
}

func (h *AuthHandler) PostRegister(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Redirect(w, r, "/cadastro?error=invalid", http.StatusFound)
		return
	}
	email := strings.TrimSpace(r.FormValue("email"))
	password := r.FormValue("password")
	name := strings.TrimSpace(r.FormValue("name"))
	if msg := auth.PasswordPolicyMessage(password); msg != "" {
		http.Redirect(w, r, "/cadastro?error=register&msg="+url.QueryEscape(msg), http.StatusFound)
		return
	}
	sess, err := h.auth.Register(r.Context(), email, password, name)
	if err != nil {
		q := url.Values{"error": {"register"}}
		if msg := registerErrorMessage(err); msg != "" {
			q.Set("msg", msg)
		}
		http.Redirect(w, r, "/cadastro?"+q.Encode(), http.StatusFound)
		return
	}
	h.auth.SetTokenCookie(w, sess.Token)
	http.Redirect(w, r, "/app/busca?welcome=1", http.StatusFound)
}

func (h *AuthHandler) PostForgotPassword(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Redirect(w, r, "/recuperar-senha?error=invalid", http.StatusFound)
		return
	}
	email := strings.TrimSpace(r.FormValue("email"))
	if email == "" {
		http.Redirect(w, r, "/recuperar-senha?error=invalid", http.StatusFound)
		return
	}
	_ = h.auth.ForgotPassword(r.Context(), email)
	http.Redirect(w, r, "/recuperar-senha?ok=1", http.StatusFound)
}

func (h *AuthHandler) PostResetPassword(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		http.Redirect(w, r, "/redefinir-senha?error=invalid", http.StatusFound)
		return
	}
	token := strings.TrimSpace(r.FormValue("token"))
	password := r.FormValue("password")
	if token == "" {
		http.Redirect(w, r, "/redefinir-senha?error=invalid&token="+url.QueryEscape(token), http.StatusFound)
		return
	}
	if msg := auth.PasswordPolicyMessage(password); msg != "" {
		q := url.Values{"error": {"reset"}, "token": {token}, "msg": {msg}}
		http.Redirect(w, r, "/redefinir-senha?"+q.Encode(), http.StatusFound)
		return
	}
	if err := h.auth.ResetPassword(r.Context(), token, password); err != nil {
		q := url.Values{"error": {"reset"}, "token": {token}}
		if msg := resetErrorMessage(err); msg != "" {
			q.Set("msg", msg)
		}
		http.Redirect(w, r, "/redefinir-senha?"+q.Encode(), http.StatusFound)
		return
	}
	http.Redirect(w, r, "/login?error=reset_ok", http.StatusFound)
}

func (h *AuthHandler) PostLogout(w http.ResponseWriter, r *http.Request) {
	token := h.auth.TokenFromRequest(r)
	if token != "" {
		h.auth.Logout(r.Context(), token)
	}
	h.auth.ClearTokenCookie(w)
	http.Redirect(w, r, "/login", http.StatusFound)
}

type AuthPageData struct {
	Mode        string
	Title       string
	Error       string
	ErrorMsg    string
	OK          string
	Next        string
	Token       string
	FormAction  string
	AltLink     string
	AltLinkText string
}

func (h *AuthHandler) renderAuth(w http.ResponseWriter, data AuthPageData) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	errMsg := ""
	switch data.Error {
	case "credentials":
		msg := data.ErrorMsg
		if msg == "" {
			msg = "E-mail ou senha inválidos."
		}
		errMsg = `<div class="alert alert-danger">` + html.EscapeString(msg) + `</div>`
	case "register":
		msg := data.ErrorMsg
		if msg == "" {
			msg = "Não foi possível criar a conta. Tente novamente."
		}
		errMsg = `<div class="alert alert-danger">` + html.EscapeString(msg) + `</div>`
	case "invalid":
		errMsg = `<div class="alert alert-danger">Dados inválidos. Verifique e tente novamente.</div>`
	case "reset":
		msg := data.ErrorMsg
		if msg == "" {
			msg = "Link expirado ou senha inválida. Use mín. 5 caracteres, com letra, número e caractere especial."
		}
		errMsg = `<div class="alert alert-danger">` + html.EscapeString(msg) + `</div>`
	case "reset_ok":
		errMsg = `<div class="alert alert-success">Senha alterada. Faça login com a nova senha.</div>`
	}
	if data.OK == "1" && data.Mode == "forgot" {
		errMsg = `<div class="alert alert-success">Se o e-mail existir, enviamos instruções para redefinir a senha.</div>`
	}
	nextField := ""
	if data.Next != "" {
		nextField = `<input type="hidden" name="next" value="` + html.EscapeString(data.Next) + `">`
	}
	tokenField := ""
	if data.Token != "" {
		tokenField = `<input type="hidden" name="token" value="` + html.EscapeString(data.Token) + `">`
	}
	body := `<!DOCTYPE html><html lang="pt-BR"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>LeadB2B | ` + html.EscapeString(data.Title) + `</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/leadb2b.css">
</head><body class="site-bg-white">
<div class="section-full p-t80 p-b80"><div class="container"><div class="row justify-content-center">
<div class="col-lg-5"><div class="p-a40 border-1">
<h2 class="mb-4">` + html.EscapeString(data.Title) + `</h2>` + errMsg + `
<form method="post" action="` + html.EscapeString(data.FormAction) + `">` + nextField + tokenField

	switch data.Mode {
	case "register":
		body += `<div class="mb-3"><label class="form-label">Nome</label>
<input class="form-control" name="name" type="text" placeholder="Seu nome"></div>`
		body += `<div class="mb-3"><label class="form-label">E-mail</label>
<input class="form-control" name="email" type="email" required placeholder="seu@email.com"></div>`
		body += authPasswordFieldHTML("Crie sua senha")
	case "forgot":
		body += `<p class="text-muted small">Informe seu e-mail. Enviaremos um link para redefinir a senha.</p>
<div class="mb-3"><label class="form-label">E-mail</label>
<input class="form-control" name="email" type="email" required placeholder="seu@email.com"></div>`
	case "reset":
		body += `<p class="text-muted small">Escolha uma nova senha seguindo os requisitos abaixo.</p>`
		body += authPasswordFieldHTML("Nova senha")
	default:
		body += `<div class="mb-3"><label class="form-label">E-mail</label>
<input class="form-control" name="email" type="email" required placeholder="seu@email.com"></div>
<div class="mb-3"><label class="form-label">Senha</label>
<input class="form-control" name="password" type="password" required minlength="10" placeholder="Sua senha"></div>
<p class="small text-end"><a href="/recuperar-senha">Esqueci minha senha</a></p>`
	}

	body += `<button type="submit" class="site-button w-100">` + html.EscapeString(data.Title) + `</button>
</form>
<p class="mt-3 text-center"><a href="` + html.EscapeString(data.AltLink) + `">` + html.EscapeString(data.AltLinkText) + `</a></p>
<p class="mt-2 text-center"><a href="/">Voltar ao site</a></p>
</div></div></div></div></div>
<script src="/static/js/password-toggle.js?v=2" defer></script>
<script src="/static/js/password-strength.js?v=1" defer></script>
</body></html>`
	w.Write([]byte(body))
}
