package storage

import (
	"fmt"
	"log"
	"os"
)

// Init creates an ObjectStore based on the configuration.
//
// Auto-detection when backend is empty:
//   - If storagePath is writable → PVC (implicit)
//   - If storagePath is missing/unwritable → nil (storage disabled)
//
// Explicit backends:
//   - "pvc" → PVC, fail if path is not writable
//   - "s3"  → S3-compatible (MinIO, Ceph RGW, AWS), fail if not reachable
func Init(backend, storagePath string, s3Cfg *S3Config) (ObjectStore, error) {
	switch backend {
	case "pvc":
		// Explicit PVC — fail if not writable
		s, err := NewPVC(storagePath)
		if err != nil {
			return nil, fmt.Errorf("storage: PVC backend at %q: %w", storagePath, err)
		}
		log.Printf("  📁 Storage: PVC at %s", storagePath)
		return s, nil

	case "s3":
		if s3Cfg == nil {
			return nil, fmt.Errorf("storage: S3 backend requires S3_BUCKET and credentials")
		}
		s, err := NewS3(*s3Cfg)
		if err != nil {
			return nil, fmt.Errorf("storage: S3 backend: %w", err)
		}
		endpoint := s3Cfg.Endpoint
		if endpoint == "" {
			endpoint = "AWS"
		}
		log.Printf("  📁 Storage: S3 at %s/%s (prefix=%q)", endpoint, s3Cfg.Bucket, s3Cfg.Prefix)
		return s, nil

	case "":
		// Auto-detect: try PVC if path exists or is creatable
		s, err := NewPVC(storagePath)
		if err != nil {
			// Path not writable — storage disabled, not an error
			log.Printf("  📁 Storage: disabled (path %s not writable)", storagePath)
			return nil, nil
		}
		log.Printf("  📁 Storage: PVC at %s (auto-detected)", storagePath)
		return s, nil

	default:
		return nil, fmt.Errorf("storage: unknown backend %q (expected pvc or s3)", backend)
	}
}

// IsPathWritable checks if a directory path exists and is writable.
// Used by auto-detection. Does not create the directory.
func IsPathWritable(path string) bool {
	info, err := os.Stat(path)
	if err != nil {
		return false
	}
	if !info.IsDir() {
		return false
	}

	// Try writing a probe file
	probe := path + "/.writable-probe"
	if err := os.WriteFile(probe, []byte("ok"), 0o644); err != nil {
		return false
	}
	os.Remove(probe)
	return true
}
