package admin

import (
	"errors"
	"time"

	"github.com/gofiber/fiber/v3"
	"gorm.io/gorm"

	"server/internal/db"
	"server/internal/responses"
	users "server/internal/user"
	"server/internal/validation"
)

type AdminController struct{}

func NewAdminController() *AdminController {
	return &AdminController{}
}

// Typescript: interface
type ListUsersRequest struct {
	Page     int `json:"page" validate:"omitempty,min=1"`
	PageSize int `json:"pageSize" validate:"omitempty,min=1,max=100"`
}

// Typescript: interface
type BlockUserRequest struct {
	Action string `json:"action" validate:"required,oneof=block unblock"`
}

// ListUsers returns a paginated list of users (requires admin permissions).
func (ac *AdminController) ListUsers(c fiber.Ctx) error {
	var req ListUsersRequest
	if err := c.Bind().Body(&req); err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
	}
	if err := validation.ValidateStruct(&req); err != nil {
		return err
	}
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 || req.PageSize > 100 {
		req.PageSize = 20
	}

	db, err := db.DBFromCtx(c)
	if err != nil {
		return err
	}

	var list []users.User
	offset := (req.Page - 1) * req.PageSize
	if err := db.Preload("Details").Preload("Preferences").
		Limit(req.PageSize).
		Offset(offset).
		Find(&list).Error; err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "failed to load users")
	}

	return c.JSON(fiber.Map{
		"data": fiber.Map{
			"page":     req.Page,
			"pageSize": req.PageSize,
			"items":    list,
		},
		"error": nil,
	})
}

// BlockUser blocks or unblocks a user account by UUID.
func (ac *AdminController) BlockUser(c fiber.Ctx) error {
	var req BlockUserRequest
	if err := c.Bind().Body(&req); err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
	}
	if err := validation.ValidateStruct(&req); err != nil {
		return err
	}

	db, err := db.DBFromCtx(c)
	if err != nil {
		return err
	}

	uuid := c.Params("uuid")
	if uuid == "" {
		return fiber.NewError(fiber.StatusBadRequest, "invalid user uuid")
	}

	var u users.User
	if err := db.Preload("Details").Preload("Preferences").Where("uuid = ?", uuid).First(&u).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fiber.NewError(fiber.StatusNotFound, "user not found")
		}
		return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
	}

	switch req.Action {
	case "block":
		u.Status = users.UserStatusDisabled
	case "unblock":
		u.Status = users.UserStatusActive
	default:
		return fiber.NewError(fiber.StatusBadRequest, "invalid action")
	}
	u.UpdatedAt = time.Now().UTC()

	if err := db.Save(&u).Error; err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "failed to update user status")
	}

	return c.JSON(responses.Success(u))
}
