package storage

import (
	"context"
	"io"

	"github.com/DeBrosOfficial/network/pkg/gateway/ctxkeys"
	"github.com/DeBrosOfficial/network/pkg/ipfs"
	"github.com/DeBrosOfficial/network/pkg/logging"
	"github.com/DeBrosOfficial/network/pkg/rqlite"
)

// IPFSClient defines the interface for interacting with IPFS.
// This interface matches the ipfs.IPFSClient implementation.
type IPFSClient interface {
	Add(ctx context.Context, reader io.Reader, name string) (*ipfs.AddResponse, error)
	Pin(ctx context.Context, cid string, name string, replicationFactor int) (*ipfs.PinResponse, error)
	PinStatus(ctx context.Context, cid string) (*ipfs.PinStatus, error)
	Get(ctx context.Context, cid string, ipfsAPIURL string) (io.ReadCloser, error)
	Unpin(ctx context.Context, cid string) error
}

// Config holds configuration values needed by storage handlers.
type Config struct {
	// IPFSReplicationFactor is the desired number of replicas for pinned content
	IPFSReplicationFactor int
	// IPFSAPIURL is the IPFS API endpoint URL
	IPFSAPIURL string
}

// Handlers provides HTTP handlers for IPFS storage operations.
// It manages file uploads, downloads, pinning, and status checking.
type Handlers struct {
	ipfsClient IPFSClient
	logger     *logging.ColoredLogger
	config     Config
	db         rqlite.Client // For tracking IPFS content ownership
}

// New creates a new storage handlers instance with the provided dependencies.
func New(ipfsClient IPFSClient, logger *logging.ColoredLogger, config Config, db rqlite.Client) *Handlers {
	return &Handlers{
		ipfsClient: ipfsClient,
		logger:     logger,
		config:     config,
		db:         db,
	}
}

// getNamespaceFromContext retrieves the namespace from the request context.
func (h *Handlers) getNamespaceFromContext(ctx context.Context) string {
	if v := ctx.Value(ctxkeys.NamespaceOverride); v != nil {
		if ns, ok := v.(string); ok {
			return ns
		}
	}
	return ""
}

// recordCIDOwnership records that a namespace owns a specific CID in the database.
// This enables namespace isolation for IPFS content.
func (h *Handlers) recordCIDOwnership(ctx context.Context, cid, namespace, name, uploadedBy string, sizeBytes int64) error {
	// Skip if no database client is available (e.g., in tests)
	if h.db == nil {
		return nil
	}

	query := `INSERT INTO ipfs_content_ownership (id, cid, namespace, name, size_bytes, is_pinned, uploaded_at, uploaded_by)
		VALUES (?, ?, ?, ?, ?, ?, datetime('now'), ?)
		ON CONFLICT(cid, namespace) DO NOTHING`

	id := cid + ":" + namespace // Simple unique ID
	_, err := h.db.Exec(ctx, query, id, cid, namespace, name, sizeBytes, false, uploadedBy)
	return err
}

// checkCIDOwnership verifies that a namespace owns (has uploaded) a specific CID.
// Returns true if the namespace owns the CID, false otherwise.
func (h *Handlers) checkCIDOwnership(ctx context.Context, cid, namespace string) (bool, error) {
	// Skip if no database client is available (e.g., in tests)
	if h.db == nil {
		return true, nil // Allow access in test mode
	}

	query := `SELECT COUNT(*) as count FROM ipfs_content_ownership WHERE cid = ? AND namespace = ?`

	var result []map[string]interface{}
	if err := h.db.Query(ctx, &result, query, cid, namespace); err != nil {
		return false, err
	}

	if len(result) == 0 {
		return false, nil
	}

	// Extract count value
	count, ok := result[0]["count"].(float64)
	if !ok {
		// Try int64
		countInt, ok := result[0]["count"].(int64)
		if ok {
			count = float64(countInt)
		}
	}

	return count > 0, nil
}

// updatePinStatus updates the pin status for a CID in the ownership table.
func (h *Handlers) updatePinStatus(ctx context.Context, cid, namespace string, isPinned bool) error {
	// Skip if no database client is available (e.g., in tests)
	if h.db == nil {
		return nil
	}

	query := `UPDATE ipfs_content_ownership SET is_pinned = ? WHERE cid = ? AND namespace = ?`
	_, err := h.db.Exec(ctx, query, isPinned, cid, namespace)
	return err
}
