package api

import (
	"encoding/json"
	"errors"
	"log/slog"
	"net/http"

	"gitea.mrixs.me/minecraft-platform/backend/internal/core"
	"gitea.mrixs.me/minecraft-platform/backend/internal/models"
	"gitea.mrixs.me/minecraft-platform/backend/internal/utils"
)

type AuthHandler struct {
	Service        *core.AuthService
	ProfileService *core.ProfileService
	Domain         string
}

// YggdrasilError - стандартный формат ошибки для authserver
type YggdrasilError struct {
	Error        string `json:"error"`
	ErrorMessage string `json:"errorMessage"`
}

func (h *AuthHandler) Authenticate(w http.ResponseWriter, r *http.Request) {
	var req models.AuthenticateRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if validationErrors := utils.ValidateStruct(req); validationErrors != nil {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(validationErrors)
		return
	}

	response, err := h.Service.Authenticate(r.Context(), req)
	if err != nil {
		if errors.Is(err, core.ErrInvalidCredentials) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusForbidden) // 403
			json.NewEncoder(w).Encode(YggdrasilError{
				Error:        "ForbiddenOperationException",
				ErrorMessage: "Invalid credentials. Invalid username or password.",
			})
			return
		}

		// Другие ошибки - внутренние
		slog.Error("internal server error during authentication", "error", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

func (h *AuthHandler) Join(w http.ResponseWriter, r *http.Request) {
	var req models.JoinRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if validationErrors := utils.ValidateStruct(req); validationErrors != nil {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(validationErrors)
		return
	}

	err := h.Service.ValidateJoinRequest(r.Context(), req)
	if err != nil {
		if errors.Is(err, core.ErrInvalidCredentials) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(YggdrasilError{
				Error:        "ForbiddenOperationException",
				ErrorMessage: "Invalid token.",
			})
			return
		}

		slog.Error("internal server error during join", "error", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
	var req models.LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if validationErrors := utils.ValidateStruct(req); validationErrors != nil {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(validationErrors)
		return
	}

	token, user, err := h.Service.LoginUser(r.Context(), req)
	if err != nil {
		if errors.Is(err, core.ErrInvalidCredentials) {
			http.Error(w, "Invalid username or password", http.StatusUnauthorized)
			return
		}
		slog.Error("internal server error during login", "error", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	response := models.LoginResponse{
		Token: token,
		User:  user,
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}

func (h *AuthHandler) GetMetadata(w http.ResponseWriter, r *http.Request) {
	pubKey, err := h.ProfileService.GetPublicKey()
	if err != nil {
		slog.Error("Failed to get public key", "error", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	metadata := models.YggdrasilMetadata{
		Meta: models.MetaLinks{
			Homepage: "https://" + h.Domain,
			Register: "https://" + h.Domain + "/register",
		},
		SkinDomains: models.MetaSkinDomains{
			Deny: []string{},
		},
		Signature: pubKey,
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(metadata)
}
