package particle_os

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/sirupsen/logrus"
)

// OSTreeStage handles OSTree-based container extraction and commit
type OSTreeStage struct {
	logger *logrus.Logger
}

// NewOSTreeStage creates a new OSTree stage
func NewOSTreeStage(logger *logrus.Logger) *OSTreeStage {
	return &OSTreeStage{
		logger: logger,
	}
}

// ExecuteOSTreeStage runs the OSTree stage
func (b *Builder) executeOSTreeStage(stage Stage, stageDir string) error {
	b.logger.Info("Executing OSTree stage")
	
	// Extract OSTree options
	ostreeRepo, _ := stage.Options["ostree_repo"].(string)
	ostreeBranch, _ := stage.Options["ostree_branch"].(string)
	ostreeRef, _ := stage.Options["ostree_ref"].(string)
	ostreeMode, _ := stage.Options["ostree_mode"].(string)
	
	if ostreeRepo == "" {
		ostreeRepo = "particle-os-repo"
	}
	if ostreeMode == "" {
		ostreeMode = "archive"
	}
	
	b.logger.Infof("OSTree configuration: repo=%s, branch=%s, ref=%s, mode=%s", 
		ostreeRepo, ostreeBranch, ostreeRef, ostreeMode)
	
	// Create OSTree repository
	repoPath := filepath.Join(b.workDir, ostreeRepo)
	if err := os.MkdirAll(repoPath, 0755); err != nil {
		return fmt.Errorf("failed to create OSTree repo directory: %w", err)
	}
	
	// Initialize OSTree repository
	initCmd := exec.Command("ostree", "init", "--repo", repoPath, "--mode", ostreeMode)
	if err := initCmd.Run(); err != nil {
		return fmt.Errorf("failed to initialize OSTree repo: %w", err)
	}
	b.logger.Info("OSTree repository initialized")
	
	// Get the rootfs directory from artifacts
	rootfsDir, exists := b.artifacts["rootfs"]
	if !exists {
		return fmt.Errorf("rootfs not found in artifacts")
	}
	
	// Create OSTree commit from the actual rootfs
	commitCmd := exec.Command("ostree", "commit", 
		"--repo", repoPath,
		"--branch", ostreeBranch,
		"--tree=dir=" + rootfsDir)
	
	if err := commitCmd.Run(); err != nil {
		return fmt.Errorf("failed to create OSTree commit: %w", err)
	}
	b.logger.Info("OSTree commit created successfully from rootfs")
	
	// Create placeholder
	placeholder := filepath.Join(stageDir, "ostree-completed")
	if err := os.WriteFile(placeholder, []byte("OSTree stage completed"), 0644); err != nil {
		return fmt.Errorf("failed to create placeholder: %w", err)
	}
	
	return nil
}

// OSTreeBootStage handles OSTree boot configuration
type OSTreeBootStage struct {
	logger *logrus.Logger
}

// NewOSTreeBootStage creates a new OSTree boot stage
func NewOSTreeBootStage(logger *logrus.Logger) *OSTreeBootStage {
	return &OSTreeBootStage{
		logger: logger,
	}
}

// ExecuteOSTreeBootStage runs the OSTree boot stage
func (b *Builder) executeOSTreeBootStage(stage Stage, stageDir string) error {
	b.logger.Info("Executing OSTree boot stage")
	
	// Extract options
	ostreeBootDir, _ := stage.Options["ostree_boot_dir"].(string)
	kernelPath, _ := stage.Options["kernel_path"].(string)
	initrdPath, _ := stage.Options["initrd_path"].(string)
	bootupdEnable, _ := stage.Options["bootupd_enable"].(bool)
	bootupdConfig, _ := stage.Options["bootupd_config"].(string)
	
	if ostreeBootDir == "" {
		ostreeBootDir = "/usr/lib/ostree-boot"
	}
	
	b.logger.Infof("OSTree boot configuration: boot_dir=%s, kernel=%s, initrd=%s", 
		ostreeBootDir, kernelPath, initrdPath)
	
	// Get rootfs directory from artifacts
	rootfsDir, exists := b.artifacts["rootfs"]
	if !exists {
		return fmt.Errorf("rootfs not found in artifacts")
	}
	
	// Create OSTree boot directory structure
	bootDir := filepath.Join(rootfsDir, ostreeBootDir)
	if err := os.MkdirAll(bootDir, 0755); err != nil {
		return fmt.Errorf("failed to create OSTree boot directory: %w", err)
	}
	
	// Configure bootupd if enabled
	if bootupdEnable {
		bootupdDir := filepath.Join(rootfsDir, "etc/bootupd")
		if err := os.MkdirAll(bootupdDir, 0755); err != nil {
			return fmt.Errorf("failed to create bootupd config directory: %w", err)
		}
		
		// Write bootupd configuration
		if bootupdConfig != "" {
			bootupdConfigPath := filepath.Join(bootupdDir, "bootupd.conf")
			if err := os.WriteFile(bootupdConfigPath, []byte(bootupdConfig), 0644); err != nil {
				return fmt.Errorf("failed to write bootupd config: %w", err)
			}
			b.logger.Info("bootupd configuration written")
		}
	}
	
	// Create placeholder
	placeholder := filepath.Join(stageDir, "ostree-boot-completed")
	if err := os.WriteFile(placeholder, []byte("OSTree boot stage completed"), 0644); err != nil {
		return fmt.Errorf("failed to create placeholder: %w", err)
	}
	
	return nil
}

// OSTreeDeployStage handles OSTree deployment configuration
type OSTreeDeployStage struct {
	logger *logrus.Logger
}

// NewOSTreeDeployStage creates a new OSTree deploy stage
func NewOSTreeDeployStage(logger *logrus.Logger) *OSTreeDeployStage {
	return &OSTreeDeployStage{
		logger: logger,
	}
}

// ExecuteOSTreeDeployStage runs the OSTree deploy stage
func (b *Builder) executeOSTreeDeployStage(stage Stage, stageDir string) error {
	b.logger.Info("Executing OSTree deploy stage")
	
	// Extract options
	ostreeRepo, _ := stage.Options["ostree_repo"].(string)
	ostreeRef, _ := stage.Options["ostree_ref"].(string)
	deploymentMode, _ := stage.Options["deployment_mode"].(string)
	immutableDirs, _ := stage.Options["immutable_dirs"].([]interface{})
	mutableDirs, _ := stage.Options["mutable_dirs"].([]interface{})
	bootloader, _ := stage.Options["bootloader"].(string)
	bootloaderConfig, _ := stage.Options["bootloader_config"].(string)
	
	if deploymentMode == "" {
		deploymentMode = "ostree"
	}
	
	b.logger.Infof("OSTree deployment: repo=%s, ref=%s, mode=%s, bootloader=%s", 
		ostreeRepo, ostreeRef, deploymentMode, bootloader)
	
	// Get rootfs directory from artifacts
	rootfsDir, exists := b.artifacts["rootfs"]
	if !exists {
		return fmt.Errorf("rootfs not found in artifacts")
	}
	
	// Configure immutable vs mutable directories
	if len(immutableDirs) > 0 {
		b.logger.Info("Configuring immutable directories")
		for _, dir := range immutableDirs {
			if dirStr, ok := dir.(string); ok {
				dirPath := filepath.Join(rootfsDir, dirStr)
				if err := os.Chmod(dirPath, 0555); err != nil {
					b.logger.Warnf("Failed to make %s immutable: %v", dirStr, err)
				}
			}
		}
	}
	
	if len(mutableDirs) > 0 {
		b.logger.Info("Configuring mutable directories")
		for _, dir := range mutableDirs {
			if dirStr, ok := dir.(string); ok {
				dirPath := filepath.Join(rootfsDir, dirStr)
				if err := os.Chmod(dirPath, 0755); err != nil {
					b.logger.Warnf("Failed to make %s mutable: %v", dirStr, err)
				}
			}
		}
	}
	
	// Configure bootloader
	if bootloader == "bootupd" && bootloaderConfig != "" {
		bootupdDir := filepath.Join(rootfsDir, "etc/bootupd")
		if err := os.MkdirAll(bootupdDir, 0755); err != nil {
			return fmt.Errorf("failed to create bootupd config directory: %w", err)
		}
		
		bootupdConfigPath := filepath.Join(bootupdDir, "bootupd.conf")
		if err := os.WriteFile(bootupdConfigPath, []byte(bootloaderConfig), 0644); err != nil {
			return fmt.Errorf("failed to write bootupd config: %w", err)
		}
		b.logger.Info("bootupd configuration written")
	}
	
	// Create placeholder
	placeholder := filepath.Join(stageDir, "ostree-deploy-completed")
	if err := os.WriteFile(placeholder, []byte("OSTree deploy stage completed"), 0644); err != nil {
		return fmt.Errorf("failed to create placeholder: %w", err)
	}
	
	return nil
}
