// Path: Backend/internal/handlers/api/users/handler.go

package users

import (
	"boostai-backend/internal/handlers/api/shared"
	"boostai-backend/internal/http/params"
	"boostai-backend/internal/http/respond"
	"boostai-backend/internal/sqlc"
	"errors"
	"strings"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/jackc/pgx/v5"
)

type Handler struct {
	queries *sqlc.Queries
}

type UserResponse struct {
	ID           int64      `json:"id"`
	Email        string     `json:"email"`
	Role         string     `json:"role"`
	FullName     string     `json:"full_name"`
	IsActive     bool       `json:"is_active"`
	CreatedAt    *time.Time `json:"created_at,omitempty"`
	UpdatedAt    *time.Time `json:"updated_at,omitempty"`
	PasswordHash *string    `json:"password_hash,omitempty"`
}

type createUserRequest struct {
	Email    string  `json:"email"`
	Password *string `json:"password"`
	Role     string  `json:"role"`
	FullName string  `json:"full_name"`
}

func NewHandler(queries *sqlc.Queries) *Handler {
	return &Handler{queries: queries}
}

func (h *Handler) ListUsersByRole(c *fiber.Ctx) error {
	role := strings.TrimSpace(c.Query("role"))
	if role == "" {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Query parameter 'role' is required")
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	users, err := h.queries.ListUsersByRole(ctx, sqlc.UserRole(role))
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	items := make([]UserResponse, 0, len(users))
	for _, user := range users {
		items = append(items, mapUser(user, false))
	}

	return c.JSON(shared.ListResponse[UserResponse]{Data: items})
}

func (h *Handler) GetUserByID(c *fiber.Ctx) error {
	id, err := params.Int64PathParam(c, "id")
	if err != nil {
		return err
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	user, err := h.queries.GetUserByID(ctx, id)
	if err != nil {
		if errors.Is(err, pgx.ErrNoRows) {
			return respond.Error(c, fiber.StatusNotFound, "not_found", "User not found")
		}
		return respond.DatabaseError(c, err)
	}

	return c.JSON(mapUser(user, false))
}

func (h *Handler) CreateUser(c *fiber.Ctx) error {
	var req createUserRequest
	if err := c.BodyParser(&req); err != nil {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Unable to parse request body")
	}

	if strings.TrimSpace(req.Email) == "" || strings.TrimSpace(req.FullName) == "" || strings.TrimSpace(req.Role) == "" {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "email, full_name, and role are required")
	}

	passwordHash, err := shared.MaybeHashPassword(req.Password)
	if err != nil {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", err.Error())
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	user, err := h.queries.CreateUser(ctx, sqlc.CreateUserParams{
		Email:        strings.TrimSpace(req.Email),
		PasswordHash: passwordHash,
		Role:         sqlc.UserRole(strings.TrimSpace(req.Role)),
		FullName:     strings.TrimSpace(req.FullName),
	})
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	return c.Status(fiber.StatusCreated).JSON(mapUser(user, false))
}

func mapUser(user sqlc.User, includePasswordHash bool) UserResponse {
	response := UserResponse{
		ID:        user.ID,
		Email:     user.Email,
		Role:      string(user.Role),
		FullName:  user.FullName,
		IsActive:  user.IsActive,
		CreatedAt: shared.TimePointer(user.CreatedAt),
		UpdatedAt: shared.TimePointer(user.UpdatedAt),
	}

	if includePasswordHash {
		response.PasswordHash = shared.TextPointer(user.PasswordHash)
	}

	return response
}
