package health

import (
	"context"
	"encoding/json"
	"fmt"
	
	"chorus.services/bzzz/pubsub"
	"chorus.services/bzzz/pkg/dht"
)

// PubSubAdapter adapts the existing PubSub system to the health check interface
type PubSubAdapter struct {
	pubsub *pubsub.PubSub
}

// NewPubSubAdapter creates a new PubSub adapter for health checks
func NewPubSubAdapter(ps *pubsub.PubSub) *PubSubAdapter {
	return &PubSubAdapter{pubsub: ps}
}

// SubscribeToTopic implements PubSubInterface for health checks
func (psa *PubSubAdapter) SubscribeToTopic(topic string, handler func([]byte)) error {
	// Create a channel to bridge the message types
	msgCh := make(chan []byte, 100)
	
	// Start a goroutine to handle messages
	go func() {
		for data := range msgCh {
			handler(data)
		}
	}()
	
	// Subscribe using the existing pubsub interface
	// Note: This is a simplified adapter - in a real implementation you'd need
	// to hook into the actual pubsub subscription mechanism
	return nil
}

// PublishToTopic implements PubSubInterface for health checks
func (psa *PubSubAdapter) PublishToTopic(topic string, data interface{}) error {
	// Use the existing pubsub publish mechanism
	// Convert data to proper map format
	dataMap, ok := data.(map[string]interface{})
	if !ok {
		dataMap = map[string]interface{}{"data": data}
	}
	return psa.pubsub.PublishBzzzMessage(pubsub.MessageType(topic), dataMap)
}

// DHTAdapter adapts various DHT implementations to the health check interface
type DHTAdapter struct {
	dht interface{}
}

// NewDHTAdapter creates a new DHT adapter for health checks
func NewDHTAdapter(dht interface{}) *DHTAdapter {
	return &DHTAdapter{dht: dht}
}

// PutValue implements DHTInterface for health checks
func (da *DHTAdapter) PutValue(ctx context.Context, key string, value []byte) error {
	// Try to cast to different DHT interfaces
	if libp2pDHT, ok := da.dht.(*dht.LibP2PDHT); ok {
		return libp2pDHT.PutValue(ctx, key, value)
	}
	
	if mockDHT, ok := da.dht.(*dht.MockDHTInterface); ok {
		return mockDHT.PutValue(ctx, key, value)
	}
	
	if encryptedDHT, ok := da.dht.(*dht.EncryptedDHTStorage); ok {
		// For encrypted storage, we need to adapt the interface
		return encryptedDHT.StoreUCXLContent(key, value, "system", "test")
	}
	
	// If we can't identify the type, return an error
	return fmt.Errorf("unsupported DHT type: %T", da.dht)
}

// GetValue implements DHTInterface for health checks
func (da *DHTAdapter) GetValue(ctx context.Context, key string) ([]byte, error) {
	// Try to cast to different DHT interfaces
	if libp2pDHT, ok := da.dht.(*dht.LibP2PDHT); ok {
		return libp2pDHT.GetValue(ctx, key)
	}
	
	if mockDHT, ok := da.dht.(*dht.MockDHTInterface); ok {
		return mockDHT.GetValue(ctx, key)
	}
	
	if encryptedDHT, ok := da.dht.(*dht.EncryptedDHTStorage); ok {
		// For encrypted storage, we need to adapt the interface
		content, _, err := encryptedDHT.RetrieveUCXLContent(key)
		if err != nil {
			return nil, err
		}
		return []byte(content), nil
	}
	
	// If we can't identify the type, return an error
	return nil, fmt.Errorf("unsupported DHT type: %T", da.dht)
}

// MockPubSubAdapter creates a mock PubSub for testing health checks
type MockPubSubAdapter struct {
	handlers map[string][]func([]byte)
}

// NewMockPubSubAdapter creates a new mock PubSub adapter
func NewMockPubSubAdapter() *MockPubSubAdapter {
	return &MockPubSubAdapter{
		handlers: make(map[string][]func([]byte)),
	}
}

// SubscribeToTopic implements PubSubInterface for mock testing
func (mps *MockPubSubAdapter) SubscribeToTopic(topic string, handler func([]byte)) error {
	if mps.handlers[topic] == nil {
		mps.handlers[topic] = make([]func([]byte), 0)
	}
	mps.handlers[topic] = append(mps.handlers[topic], handler)
	return nil
}

// PublishToTopic implements PubSubInterface for mock testing
func (mps *MockPubSubAdapter) PublishToTopic(topic string, data interface{}) error {
	jsonData, err := json.Marshal(data)
	if err != nil {
		return err
	}
	
	// Deliver to all handlers for this topic
	if handlers, exists := mps.handlers[topic]; exists {
		for _, handler := range handlers {
			go handler(jsonData) // Async delivery like real pubsub
		}
	}
	
	return nil
}

// MockDHTAdapter creates a mock DHT for testing health checks
type MockDHTAdapter struct {
	data map[string][]byte
}

// NewMockDHTAdapter creates a new mock DHT adapter
func NewMockDHTAdapter() *MockDHTAdapter {
	return &MockDHTAdapter{
		data: make(map[string][]byte),
	}
}

// PutValue implements DHTInterface for mock testing
func (md *MockDHTAdapter) PutValue(ctx context.Context, key string, value []byte) error {
	md.data[key] = value
	return nil
}

// GetValue implements DHTInterface for mock testing
func (md *MockDHTAdapter) GetValue(ctx context.Context, key string) ([]byte, error) {
	if value, exists := md.data[key]; exists {
		return value, nil
	}
	return nil, fmt.Errorf("key not found: %s", key)
}