package nfs

import (
	"fmt"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
)

// Manager управляет NFS монтированием
type Manager struct {
	mu         sync.RWMutex
	enabled    bool
	server     string
	exportPath string
	mountPoint string
	options    string
	mounted    bool
	mountTime  time.Time
}

var (
	// DefaultManager - глобальный менеджер NFS
	DefaultManager *Manager
	initOnce       sync.Once
)

// Config конфигурация NFS
type Config struct {
	Enabled    bool
	Server     string
	ExportPath string
	MountPoint string
	Options    string
}

// Init инициализирует глобальный менеджер NFS
func Init(cfg Config) {
	initOnce.Do(func() {
		DefaultManager = &Manager{
			enabled:    cfg.Enabled,
			server:     cfg.Server,
			exportPath: cfg.ExportPath,
			mountPoint: cfg.MountPoint,
			options:    cfg.Options,
			mounted:    false,
		}
		
		if cfg.Enabled {
			logrus.Infof("NFS manager initialized: %s:%s -> %s", 
				cfg.Server, cfg.ExportPath, cfg.MountPoint)
		} else {
			logrus.Info("NFS manager initialized but disabled")
		}
	})
}

// IsEnabled возвращает статус включения NFS
func (m *Manager) IsEnabled() bool {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.enabled
}

// IsMounted проверяет, смонтирован ли NFS
func (m *Manager) IsMounted() bool {
	m.mu.RLock()
	defer m.mu.RUnlock()
	
	if !m.mounted {
		return false
	}
	
	// Проверяем актуальность монтирования через filesystem
	return checkMountPoint(m.mountPoint)
}

// Mount монтирует NFS share
func (m *Manager) Mount() error {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	if !m.enabled {
		logrus.Debug("NFS mounting skipped: disabled")
		return nil
	}
	
	// Проверяем, уже ли смонтировано
	if checkMountPoint(m.mountPoint) {
		logrus.Debugf("NFS already mounted at %s", m.mountPoint)
		m.mounted = true
		m.mountTime = time.Now()
		return nil
	}
	
	logrus.Infof("Attempting to mount NFS: %s:%s -> %s", 
		m.server, m.exportPath, m.mountPoint)
	
	// Создаем точку монтирования если не существует
	if err := os.MkdirAll(m.mountPoint, 0755); err != nil {
		logrus.Errorf("Failed to create mount point %s: %v", m.mountPoint, err)
		return fmt.Errorf("failed to create mount point: %w", err)
	}
	
	// Формируем опции монтирования
	mountOptions := m.options
	if mountOptions == "" {
		mountOptions = "rw,vers=4.1,timeo=50,retrans=2"
	}
	
	// Выполняем команду mount
	cmd := exec.Command("mount", "-t", "nfs", 
		fmt.Sprintf("%s:%s", m.server, m.exportPath),
		m.mountPoint,
		"-o", mountOptions)
	
	output, err := cmd.CombinedOutput()
	if err != nil {
		logrus.Errorf("Failed to mount NFS: %v, output: %s", err, string(output))
		m.mounted = false
		return fmt.Errorf("failed to mount NFS: %w, output: %s", err, string(output))
	}
	
	m.mounted = true
	m.mountTime = time.Now()
	logrus.Infof("NFS mounted successfully: %s:%s -> %s", 
		m.server, m.exportPath, m.mountPoint)
	
	return nil
}

// Unmount размонтирует NFS share
func (m *Manager) Unmount() error {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	if !m.enabled {
		logrus.Debug("NFS unmounting skipped: disabled")
		return nil
	}
	
	logrus.Infof("Unmounting NFS from %s", m.mountPoint)
	
	cmd := exec.Command("umount", m.mountPoint)
	output, err := cmd.CombinedOutput()
	if err != nil {
		logrus.Errorf("Failed to unmount NFS: %v, output: %s", err, string(output))
		return fmt.Errorf("failed to unmount NFS: %w, output: %s", err, string(output))
	}
	
	m.mounted = false
	logrus.Infof("NFS unmounted successfully from %s", m.mountPoint)
	
	return nil
}

// CheckHealth проверяет доступность NFS mount point
func (m *Manager) CheckHealth() error {
	m.mu.RLock()
	defer m.mu.RUnlock()
	
	if !m.enabled {
		return nil
	}
	
	return checkMountPointWithDetails(m.mountPoint)
}

// Remount пытается перемонтировать NFS если он размонтирован
func (m *Manager) Remount() error {
	if !m.IsMounted() {
		logrus.Warn("NFS not mounted, attempting remount...")
		return m.Mount()
	}
	return nil
}

// GetMountPoint возвращает точку монтирования
func (m *Manager) GetMountPoint() string {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.mountPoint
}

// checkMountPoint проверяет, смонтирована ли точка
func checkMountPoint(mountPoint string) bool {
	// Проверяем через statfs (на Linux)
	// Если точка смонтирована, то она будет иметь другой device ID чем родитель
	cmd := exec.Command("mountpoint", "-q", mountPoint)
	err := cmd.Run()
	return err == nil
}

// checkMountPointWithDetails проверяет с логированием
func checkMountPointWithDetails(mountPoint string) error {
	if !checkMountPoint(mountPoint) {
		return fmt.Errorf("mount point %s is not mounted", mountPoint)
	}
	return nil
}

// EnsureMounted гарантирует что NFS смонтирован, монтирует если нужно
func EnsureMounted() error {
	if DefaultManager == nil {
		logrus.Debug("NFS manager not initialized")
		return nil
	}
	return DefaultManager.Remount()
}
