package handlers

import (
	"time"

	"Noooste/garage-ui/internal/models"
	"Noooste/garage-ui/internal/services"

	"github.com/gofiber/fiber/v3"
)

// UserHandler handles user and access key HTTP requests.
type UserHandler struct {
	adminService services.AdminService
}

// NewUserHandler creates a new user handler.
func NewUserHandler(adminService services.AdminService) *UserHandler {
	return &UserHandler{
		adminService: adminService,
	}
}

// ListUsers lists all users/access keys
//
//	@Summary		List all users
//	@Description	Retrieves a list of all users/access keys
//	@Tags			Users
//	@Produce		json
//	@Success		200	{object}	models.APIResponse{data=models.UserListResponse}	"List of users retrieved successfully"
//	@Failure		500	{object}	models.APIResponse{error=models.APIError}			"Failed to list users"
//	@Router			/api/v1/users [get]
func (h *UserHandler) ListUsers(c fiber.Ctx) error {
	ctx := c.Context()

	keys, err := h.adminService.ListKeys(ctx)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to list users: "+err.Error()),
		)
	}

	// Convert to UserInfo format
	users := make([]models.UserInfo, 0, len(keys))
	for _, key := range keys {
		// Get full key info to retrieve bucket permissions
		keyInfo, err := h.adminService.GetKeyInfo(ctx, key.ID, false)
		if err != nil {
			// If we can't get full info, skip this key or use basic info
			continue
		}

		// Convert bucket permissions to frontend format
		bucketPermissions := convertBucketPermissionsToBucketPermissions(keyInfo.Buckets)

		// Determine status based on expiration
		status := "active"
		if keyInfo.Expired {
			status = "inactive"
		}

		users = append(users, models.UserInfo{
			AccessKeyID:       keyInfo.AccessKeyID,
			Name:              keyInfo.Name,
			CreatedAt:         keyInfo.Created,
			Status:            status,
			BucketPermissions: bucketPermissions,
			Expiration:        keyInfo.Expiration,
			Expired:           keyInfo.Expired,
		})
	}

	return c.JSON(models.SuccessResponse(models.UserListResponse{
		Users: users,
		Count: len(users),
	}))
}

// convertBucketPermissionsToBucketPermissions converts Garage bucket permissions to frontend BucketPermission format
func convertBucketPermissionsToBucketPermissions(buckets []models.KeyBucketInfo) []models.BucketPermission {
	permissions := make([]models.BucketPermission, 0, len(buckets))

	for _, bucket := range buckets {
		// Get bucket name from aliases
		var bucketName string
		if len(bucket.GlobalAliases) > 0 {
			bucketName = bucket.GlobalAliases[0]
		} else if len(bucket.LocalAliases) > 0 {
			bucketName = bucket.LocalAliases[0]
		} else {
			bucketName = bucket.ID
		}

		// Create bucket permission with simple read/write/owner flags
		permissions = append(permissions, models.BucketPermission{
			BucketID:   bucket.ID,
			BucketName: bucketName,
			Read:       bucket.Permissions.Read,
			Write:      bucket.Permissions.Write,
			Owner:      bucket.Permissions.Owner,
		})
	}

	return permissions
}

// CreateUser creates a new user/access key
//
//	@Summary		Create a new user
//	@Description	Creates a new user/access key with optional name
//	@Tags			Users
//	@Accept			json
//	@Produce		json
//	@Param			request	body		models.CreateUserRequest					true	"User creation request"
//	@Success		201		{object}	models.APIResponse{data=models.UserInfo}	"User created successfully"
//	@Failure		400		{object}	models.APIResponse{error=models.APIError}	"Invalid request body"
//	@Failure		500		{object}	models.APIResponse{error=models.APIError}	"Failed to create user"
//	@Router			/api/v1/users [post]
func (h *UserHandler) CreateUser(c fiber.Ctx) error {
	ctx := c.Context()

	var req models.CreateUserRequest
	if err := c.Bind().JSON(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Invalid request body: "+err.Error()),
		)
	}

	// Prepare create key request
	createReq := models.CreateKeyRequest{}
	if req.Name != "" {
		createReq.Name = &req.Name
	}

	// Create the key
	keyInfo, err := h.adminService.CreateKey(ctx, createReq)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to create user: "+err.Error()),
		)
	}

	// Convert bucket permissions to frontend format
	bucketPermissions := convertBucketPermissionsToBucketPermissions(keyInfo.Buckets)

	// Determine status
	status := "active"
	if keyInfo.Expired {
		status = "inactive"
	}

	// Convert to UserInfo format
	userInfo := models.UserInfo{
		AccessKeyID:       keyInfo.AccessKeyID,
		SecretKey:         keyInfo.SecretAccessKey,
		Name:              keyInfo.Name,
		CreatedAt:         keyInfo.Created,
		Status:            status,
		BucketPermissions: bucketPermissions,
		Expiration:        keyInfo.Expiration,
		Expired:           keyInfo.Expired,
	}

	return c.Status(fiber.StatusCreated).JSON(models.SuccessResponse(userInfo))
}

// DeleteUser deletes a user/access key
//
//	@Summary		Delete a user
//	@Description	Deletes a specific user/access key
//	@Tags			Users
//	@Produce		json
//	@Param			access_key	path		string											true	"Access key of the user to delete"
//	@Success		200			{object}	models.APIResponse{data=map[string]interface{}}	"User deleted successfully"
//	@Failure		400			{object}	models.APIResponse{error=models.APIError}		"Access key is required"
//	@Failure		500			{object}	models.APIResponse{error=models.APIError}		"Failed to delete user"
//	@Router			/api/v1/users/{access_key} [delete]
func (h *UserHandler) DeleteUser(c fiber.Ctx) error {
	ctx := c.Context()
	accessKey := c.Params("access_key")

	if accessKey == "" {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Access key is required"),
		)
	}

	// Delete the key
	err := h.adminService.DeleteKey(ctx, accessKey)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to delete user: "+err.Error()),
		)
	}

	return c.JSON(models.SuccessResponse(map[string]interface{}{
		"access_key": accessKey,
		"deleted":    true,
	}))
}

// GetUser retrieves information about a specific user/access key
//
//	@Summary		Get user information
//	@Description	Retrieves information about a specific user/access key
//	@Tags			Users
//	@Produce		json
//	@Param			access_key	path		string										true	"Access key of the user to retrieve"
//	@Success		200			{object}	models.APIResponse{data=models.UserInfo}	"User information retrieved successfully"
//	@Failure		400			{object}	models.APIResponse{error=models.APIError}	"Access key is required"
//	@Failure		500			{object}	models.APIResponse{error=models.APIError}	"Failed to get user info"
//	@Router			/api/v1/users/{access_key} [get]
func (h *UserHandler) GetUser(c fiber.Ctx) error {
	ctx := c.Context()
	accessKey := c.Params("access_key")

	if accessKey == "" {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Access key is required"),
		)
	}

	// Get key information (without secret key)
	keyInfo, err := h.adminService.GetKeyInfo(ctx, accessKey, false)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to get user info: "+err.Error()),
		)
	}

	// Convert bucket permissions to frontend format
	bucketPermissions := convertBucketPermissionsToBucketPermissions(keyInfo.Buckets)

	// Determine status
	status := "active"
	if keyInfo.Expired {
		status = "inactive"
	}

	// Convert to UserInfo format
	userInfo := models.UserInfo{
		AccessKeyID:       keyInfo.AccessKeyID,
		Name:              keyInfo.Name,
		CreatedAt:         keyInfo.Created,
		Status:            status,
		BucketPermissions: bucketPermissions,
		Expiration:        keyInfo.Expiration,
		Expired:           keyInfo.Expired,
	}

	return c.JSON(models.SuccessResponse(userInfo))
}

// GetUserSecretKey retrieves the secret key for a specific user/access key
//
//	@Summary		Get user secret key
//	@Description	Retrieves the secret access key for a specific user/access key
//	@Tags			Users
//	@Produce		json
//	@Param			access_key	path		string										true	"Access key of the user to retrieve secret for"
//	@Success		200			{object}	models.APIResponse{data=map[string]string}	"Secret key retrieved successfully"
//	@Failure		400			{object}	models.APIResponse{error=models.APIError}	"Access key is required"
//	@Failure		500			{object}	models.APIResponse{error=models.APIError}	"Failed to get secret key"
//	@Router			/api/v1/users/{access_key}/secret [get]
func (h *UserHandler) GetUserSecretKey(c fiber.Ctx) error {
	ctx := c.Context()
	accessKey := c.Params("access_key")

	if accessKey == "" {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Access key is required"),
		)
	}

	// Get key information WITH secret key
	keyInfo, err := h.adminService.GetKeyInfo(ctx, accessKey, true)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to get secret key: "+err.Error()),
		)
	}

	// Return only the secret key
	return c.JSON(models.SuccessResponse(map[string]string{
		"secretKey": *keyInfo.SecretAccessKey,
	}))
}

// UpdateUserPermissions updates user permissions
//
//	@Summary		Update user permissions
//	@Description	Updates the permissions and settings for a specific user/access key
//	@Tags			Users
//	@Accept			json
//	@Produce		json
//	@Param			access_key	path		string										true	"Access key of the user to update"
//	@Param			request		body		models.UpdateUserRequest					true	"User update request with new permissions"
//	@Success		200			{object}	models.APIResponse{data=models.UserInfo}	"User updated successfully"
//	@Failure		400			{object}	models.APIResponse{error=models.APIError}	"Access key is required or invalid request body"
//	@Failure		500			{object}	models.APIResponse{error=models.APIError}	"Failed to update user"
//	@Router			/api/v1/users/{access_key} [patch]
func (h *UserHandler) UpdateUserPermissions(c fiber.Ctx) error {
	ctx := c.Context()
	accessKey := c.Params("access_key")

	if accessKey == "" {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Access key is required"),
		)
	}

	var req models.UpdateUserRequest
	if err := c.Bind().JSON(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(
			models.ErrorResponse(models.ErrCodeBadRequest, "Invalid request body: "+err.Error()),
		)
	}

	// Prepare update request
	updateReq := models.UpdateKeyRequest{}

	// Handle status change (activate/deactivate)
	if req.Status != nil {
		if *req.Status == "inactive" {
			// Deactivate by setting expiration to the past
			pastTime := time.Now().Add(-24 * time.Hour)
			updateReq.Expiration = &pastTime
			updateReq.NeverExpires = false
		} else if *req.Status == "active" {
			// Activate by removing expiration (set to never expire)
			updateReq.NeverExpires = true
		}
	}

	// Handle explicit expiration date setting
	if req.Expiration != nil && *req.Expiration != "" {
		expirationTime, err := time.Parse(time.RFC3339, *req.Expiration)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(
				models.ErrorResponse(models.ErrCodeBadRequest, "Invalid expiration date format: "+err.Error()),
			)
		}
		updateReq.Expiration = &expirationTime
		updateReq.NeverExpires = false
	}

	// Update the key
	keyInfo, err := h.adminService.UpdateKey(ctx, accessKey, updateReq)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(
			models.ErrorResponse(models.ErrCodeInternalError, "Failed to update user: "+err.Error()),
		)
	}

	// Convert bucket permissions to frontend format
	bucketPermissions := convertBucketPermissionsToBucketPermissions(keyInfo.Buckets)

	// Determine status
	status := "active"
	if keyInfo.Expired {
		status = "inactive"
	}

	// Convert to UserInfo format
	userInfo := models.UserInfo{
		AccessKeyID:       keyInfo.AccessKeyID,
		Name:              keyInfo.Name,
		CreatedAt:         keyInfo.Created,
		Status:            status,
		BucketPermissions: bucketPermissions,
		Expiration:        keyInfo.Expiration,
		Expired:           keyInfo.Expired,
	}

	return c.JSON(models.SuccessResponse(userInfo))
}
