package olric

import (
	"context"
	"fmt"
	"time"

	olriclib "github.com/olric-data/olric"
	"go.uber.org/zap"
)

// Client wraps an Olric cluster client for distributed cache operations
type Client struct {
	client olriclib.Client
	logger *zap.Logger
}

// Config holds configuration for the Olric client
type Config struct {
	// Servers is a list of Olric server addresses (e.g., ["localhost:3320"])
	// If empty, defaults to ["localhost:3320"]
	Servers []string

	// Timeout is the timeout for client operations
	// If zero, defaults to 10 seconds
	Timeout time.Duration
}

// NewClient creates a new Olric client wrapper
func NewClient(cfg Config, logger *zap.Logger) (*Client, error) {
	servers := cfg.Servers
	if len(servers) == 0 {
		servers = []string{"localhost:3320"}
	}

	client, err := olriclib.NewClusterClient(servers)
	if err != nil {
		return nil, fmt.Errorf("failed to create Olric cluster client: %w", err)
	}

	timeout := cfg.Timeout
	if timeout == 0 {
		timeout = 10 * time.Second
	}

	return &Client{
		client: client,
		logger: logger,
	}, nil
}

// UnderlyingClient returns the underlying olriclib.Client for advanced usage.
// This is useful when you need to pass the client to other packages that expect
// the raw olric client interface.
func (c *Client) UnderlyingClient() olriclib.Client {
	return c.client
}

// Health checks if the Olric client is healthy
func (c *Client) Health(ctx context.Context) error {
	// Create a DMap to test connectivity
	dm, err := c.client.NewDMap("_health_check")
	if err != nil {
		return fmt.Errorf("failed to create DMap for health check: %w", err)
	}

	// Try a simple put/get operation
	testKey := fmt.Sprintf("_health_%d", time.Now().UnixNano())
	testValue := "ok"

	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	err = dm.Put(ctx, testKey, testValue)
	if err != nil {
		return fmt.Errorf("health check put failed: %w", err)
	}

	gr, err := dm.Get(ctx, testKey)
	if err != nil {
		return fmt.Errorf("health check get failed: %w", err)
	}

	val, err := gr.String()
	if err != nil {
		return fmt.Errorf("health check value decode failed: %w", err)
	}

	if val != testValue {
		return fmt.Errorf("health check value mismatch: expected %q, got %q", testValue, val)
	}

	// Clean up test key
	_, _ = dm.Delete(ctx, testKey)

	return nil
}

// Close closes the Olric client connection
func (c *Client) Close(ctx context.Context) error {
	if c.client == nil {
		return nil
	}
	return c.client.Close(ctx)
}

// GetClient returns the underlying Olric client
func (c *Client) GetClient() olriclib.Client {
	return c.client
}
