//go:build linux

package installer

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

	"gitgud.io/mike/mpv-manager/internal/assets"
	"gitgud.io/mike/mpv-manager/pkg/config"
	"gitgud.io/mike/mpv-manager/pkg/constants"
	"gitgud.io/mike/mpv-manager/pkg/log"
	"gitgud.io/mike/mpv-manager/pkg/platform"
)

type LinuxInstaller struct {
	*Installer
	Platform *platform.Platform
}

func (li *LinuxInstaller) getPrivilegePrefix() []string {
	return GetPrivilegePrefix()
}

func NewLinuxInstaller(installer *Installer, p *platform.Platform) *LinuxInstaller {
	return &LinuxInstaller{
		Installer: installer,
		Platform:  p,
	}
}

func (li *LinuxInstaller) GetAvailableMethods(filterInstalled bool) []InstallMethod {
	methods := []InstallMethod{}

	if li.Platform.IsImmutableDistro() {
		if filterInstalled && config.IsAppInstalled("Celluloid") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodCelluloidFlatpak,
				Name:        "Celluloid",
				Description: "Modern MPV frontend via Flatpak from Flathub",
				Recommended: true,
				Priority:    1,
				Icon:        constants.MethodIcon[constants.MethodCelluloidFlatpak],
				Logo:        constants.MethodLogo[constants.MethodCelluloidFlatpak],
				Type:        constants.MethodType[constants.MethodCelluloidFlatpak],
				AppType:     constants.MethodAppType[constants.MethodCelluloidFlatpak],
				Homepage:    constants.MethodHomepage[constants.MethodCelluloidFlatpak],
			})
		}

		if filterInstalled && config.IsAppInstalled("MPV") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodMPVFlatpak,
				Name:        "MPV",
				Description: "Official MPV via Flatpak from Flathub",
				Recommended: true,
				Priority:    2,
				Icon:        constants.MethodIcon[constants.MethodMPVFlatpak],
				Logo:        constants.MethodLogo[constants.MethodMPVFlatpak],
				Type:        constants.MethodType[constants.MethodMPVFlatpak],
				AppType:     constants.MethodAppType[constants.MethodMPVFlatpak],
				Homepage:    constants.MethodHomepage[constants.MethodMPVFlatpak],
			})
		}
	} else {
		if filterInstalled && config.IsAppInstalled("Celluloid") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodCelluloidPackage,
				Name:        "Celluloid",
				Description: "Install via package manager",
				Recommended: true,
				Priority:    1,
				Icon:        constants.MethodIcon[constants.MethodCelluloidPackage],
				Logo:        constants.MethodLogo[constants.MethodCelluloidPackage],
				Type:        constants.MethodType[constants.MethodCelluloidPackage],
				AppType:     constants.MethodAppType[constants.MethodCelluloidPackage],
				Homepage:    constants.MethodHomepage[constants.MethodCelluloidPackage],
			})
		}

		if filterInstalled && config.IsAppInstalled("Celluloid") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodCelluloidFlatpak,
				Name:        "Celluloid",
				Description: "Modern MPV frontend via Flatpak from Flathub",
				Recommended: true,
				Priority:    2,
				Icon:        constants.MethodIcon[constants.MethodCelluloidFlatpak],
				Logo:        constants.MethodLogo[constants.MethodCelluloidFlatpak],
				Type:        constants.MethodType[constants.MethodCelluloidFlatpak],
				AppType:     constants.MethodAppType[constants.MethodCelluloidFlatpak],
				Homepage:    constants.MethodHomepage[constants.MethodCelluloidFlatpak],
			})
		}

		if filterInstalled && config.IsAppInstalled("MPV") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodMPVPackage,
				Name:        "MPV",
				Description: "Install via package manager",
				Recommended: true,
				Priority:    3,
				Icon:        constants.MethodIcon[constants.MethodMPVPackage],
				Logo:        constants.MethodLogo[constants.MethodMPVPackage],
				Type:        constants.MethodType[constants.MethodMPVPackage],
				AppType:     constants.MethodAppType[constants.MethodMPVPackage],
				Homepage:    constants.MethodHomepage[constants.MethodMPVPackage],
			})
		}

		if filterInstalled && config.IsAppInstalled("MPV") {
		} else {
			methods = append(methods, InstallMethod{
				ID:          constants.MethodMPVFlatpak,
				Name:        "MPV",
				Description: "Official MPV via Flatpak from Flathub",
				Recommended: false,
				Priority:    4,
				Icon:        constants.MethodIcon[constants.MethodMPVFlatpak],
				Logo:        constants.MethodLogo[constants.MethodMPVFlatpak],
				Type:        constants.MethodType[constants.MethodMPVFlatpak],
				AppType:     constants.MethodAppType[constants.MethodMPVFlatpak],
				Homepage:    constants.MethodHomepage[constants.MethodMPVFlatpak],
			})
		}
	}

	return methods
}

func (li *LinuxInstaller) CheckFlatpakInstalled() bool {
	_, err := exec.LookPath("flatpak")
	return err == nil
}

func (li *LinuxInstaller) CheckFlathubEnabled() bool {
	cmd := exec.Command("flatpak", "remote-list")
	output, err := cmd.Output()
	if err != nil {
		return false
	}
	return strings.Contains(string(output), "flathub")
}

func (li *LinuxInstaller) EnableFlathub() error {
	cmd := exec.Command("flatpak", "remote-add", "--if-not-exists", "flathub", "https://flathub.org/repo/flathub.flatpakrepo")
	return cmd.Run()
}

func (li *LinuxInstaller) InstallFlatpak(flatpakID string, installUOSC bool) error {
	if !li.CheckFlatpakInstalled() {
		log.Warn("Flatpak is not installed, cannot install " + flatpakID)
		return fmt.Errorf("flatpak is not installed. Please install flatpak first.")
	}

	if !li.CheckFlathubEnabled() {
		fmt.Println("Enabling Flathub...")
		log.Info("Enabling Flathub repository...")
		cmd := exec.Command("flatpak", "remote-add", "--if-not-exists", "flathub", "https://flathub.org/repo/flathub.flatpakrepo")
		cmd.Stdin = os.Stdin
		if err := cmd.Run(); err != nil {
			log.Warn("Failed to enable Flathub: " + err.Error())
			return fmt.Errorf("failed to enable flathub: %w", err)
		}
		log.Info("Flathub enabled successfully")
	}

	fmt.Printf("Installing %s via Flatpak...\n", flatpakID)
	log.Info("Installing " + flatpakID + " via Flatpak from Flathub...")
	cmd := exec.Command("flatpak", "install", "flathub", flatpakID, "-y")
	cmd.Stdin = os.Stdin
	if err := cmd.Run(); err != nil {
		log.Error("Flatpak install failed for " + flatpakID + ": " + err.Error())
		return fmt.Errorf("flatpak install failed: %w", err)
	}
	log.Info(flatpakID + " installed successfully via Flatpak")
	return nil
}

func (li *LinuxInstaller) CheckInstalled() bool {
	_, err := exec.LookPath("mpv")
	return err == nil
}

func (li *LinuxInstaller) CanUpdate() bool {
	return li.CheckInstalled()
}

func (li *LinuxInstaller) GetInstalledVersion() string {
	cmd := exec.Command("mpv", "--version")
	output, err := cmd.Output()
	if err != nil {
		return ""
	}
	lines := strings.Split(string(output), "\n")
	if len(lines) > 0 {
		return strings.TrimPrefix(lines[0], "mpv ")
	}
	return ""
}

func (li *LinuxInstaller) Uninstall() error {
	switch li.Platform.DistroFamily {
	case "debian":
		if _, err := exec.LookPath("apt"); err == nil {
			cmd := exec.Command("sudo", "apt", "remove", "-y", constants.PackageMPV, constants.PackageCelluloid)
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			return cmd.Run()
		}
	case "rhel":
		if _, err := exec.LookPath("dnf"); err == nil {
			cmd := exec.Command("sudo", "dnf", "remove", "-y", constants.PackageMPV, constants.PackageCelluloid)
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			return cmd.Run()
		}
	case "arch":
		if _, err := exec.LookPath("pacman"); err == nil {
			cmd := exec.Command("sudo", "pacman", "-Rns", "--noconfirm", constants.PackageMPV, constants.PackageCelluloid)
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			return cmd.Run()
		}
	}

	if _, err := exec.LookPath("flatpak"); err == nil {
		cmd := exec.Command("flatpak", "uninstall", "-y", constants.FlatpakMPV, constants.FlatpakCelluloid)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Run()
	}

	return os.RemoveAll(li.InstallDir)
}

func (li *LinuxInstaller) UninstallFlatpak(appID string) error {
	cmd := exec.Command("flatpak", "uninstall", "-y", appID)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (li *LinuxInstaller) UninstallBrew(appName string) error {
	if _, err := exec.LookPath("brew"); err != nil {
		return fmt.Errorf("homebrew is not installed")
	}
	cmd := exec.Command("brew", "uninstall", appName)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (li *LinuxInstaller) InstallFlatpakWithOutput(cr *CommandRunner, flatpakID string, uiType string, isUpdate bool) error {
	// Auto-install flatpak if not present
	if !li.CheckFlatpakInstalled() {
		cr.outputChan <- "Flatpak is not installed. Installing automatically..."

		// Determine package name based on distro family
		var flatpakPkg string
		switch li.Platform.DistroFamily {
		case "debian":
			flatpakPkg = "flatpak"
		case "rhel":
			flatpakPkg = "flatpak"
		case "arch":
			flatpakPkg = "flatpak"
		default:
			return fmt.Errorf("unsupported distribution family for auto-installing flatpak: %s", li.Platform.DistroFamily)
		}

		cr.outputChan <- fmt.Sprintf("Installing %s via package manager (requires sudo)...", flatpakPkg)

		// Build the package manager install command
		pm := NewPackageManager(li.Platform.DistroFamily)
		installCmd := pm.BuildInstallCommand(flatpakPkg, false) // false = no privilege prefix, we use RunSudoCommand

		if len(installCmd) == 0 {
			return fmt.Errorf("failed to build install command for flatpak")
		}

		// Use RunSudoCommand which handles keyring password authentication
		if err := cr.RunSudoCommand(installCmd[0], installCmd[1:]...); err != nil {
			cr.outputChan <- fmt.Sprintf("Failed to install flatpak: %v", err)
			return fmt.Errorf("failed to install flatpak: %w", err)
		}

		cr.outputChan <- "✓ Flatpak installed successfully"
		cr.outputChan <- ""
		cr.outputChan <- "⚠️  NOTICE: Flatpak was just installed."
		cr.outputChan <- "   You may need to restart your session or run 'flatpak update' for"
		cr.outputChan <- "   application icons to appear in your desktop menu."
		cr.outputChan <- ""

		// Set pending notice for Web UI
		SetPendingNotice("Flatpak was just installed. You may need to restart your session or run 'flatpak update' for application icons to appear in your desktop menu.")
	}

	if isUpdate {
		cr.outputChan <- fmt.Sprintf("Updating %s via Flatpak...", flatpakID)
		cmd := cr.RunCommand("flatpak", "update", flatpakID, "-y")
		if cmd != nil {
			return cmd
		}

		if isMPVInstall(flatpakID) {
			cr.outputChan <- constants.MsgConfigNotOverwritten
		}
		return nil
	}

	// Auto-enable Flathub if not present
	if !li.CheckFlathubEnabled() {
		cr.outputChan <- "Enabling Flathub repository..."
		cmd := cr.RunCommand("flatpak", "remote-add", "--if-not-exists", "flathub", "https://flathub.org/repo/flathub.flatpakrepo")
		if cmd != nil {
			return cmd
		}
		cr.outputChan <- "✓ Flathub enabled"
	}

	cr.outputChan <- fmt.Sprintf("Installing %s via Flatpak...", flatpakID)
	cmd := cr.RunCommand("flatpak", "install", "flathub", flatpakID, "-y")
	if cmd != nil {
		return cmd
	}

	if isMPVInstall(flatpakID) && uiType != constants.UITypeNone {
		homeDir, err := os.UserHomeDir()
		if err != nil {
			return err
		}
		configDir := GetMPVConfigDirFromHome(homeDir)
		InstallUISafely(li.Installer, cr, configDir, uiType)
	}

	// Configure flatpak filesystem access for user's mpv config directory
	if isMPVInstall(flatpakID) {
		if err := li.ConfigureMPVFlatpakWithOutput(cr); err != nil {
			cr.outputChan <- fmt.Sprintf("Warning: Failed to configure MPV Flatpak: %v", err)
		}
	} else if flatpakID == constants.FlatpakCelluloid {
		if err := li.ConfigureCelluloidFlatpakWithOutput(cr); err != nil {
			cr.outputChan <- fmt.Sprintf("Warning: Failed to configure Celluloid Flatpak: %v", err)
		}
	}

	return nil
}

func (li *LinuxInstaller) GetDefaultInstallPath() string {
	homeDir, _ := os.UserHomeDir()
	return filepath.Join(homeDir, "Downloads", "mpv")
}

func (li *LinuxInstaller) NormalizePath(path string) string {
	return filepath.Clean(path)
}

func (li *LinuxInstaller) UninstallFlatpakWithOutput(cr *CommandRunner, appID string) error {
	cr.outputChan <- fmt.Sprintf("Uninstalling %s via Flatpak...", appID)
	cmd := cr.RunCommand("flatpak", "uninstall", "-y", appID)
	if err := cmd; err != nil {
		return fmt.Errorf("flatpak uninstall failed: %w", err)
	}
	return nil
}

func (li *LinuxInstaller) UninstallBrewWithOutput(cr *CommandRunner, appName string) error {
	if _, err := exec.LookPath("brew"); err != nil {
		return fmt.Errorf("homebrew is not installed")
	}
	cr.outputChan <- fmt.Sprintf("Uninstalling %s via Homebrew...", appName)
	cmd := cr.RunCommand("brew", "uninstall", appName)
	if err := cmd; err != nil {
		return fmt.Errorf("brew uninstall failed: %w", err)
	}
	return nil
}

func (li *LinuxInstaller) EnsureGSettingsInstalled(cr *CommandRunner) error {
	if _, err := exec.LookPath(constants.CommandGsettings); err == nil {
		cr.outputChan <- "gsettings is already installed"
		return nil
	}

	cr.outputChan <- "gsettings not found, installing gsettings-desktop-schemas..."

	packageManager := NewPackageManager(li.Platform.DistroFamily)
	// Build command WITHOUT sudo prefix - RunSudoCommand handles authentication
	installCmd := packageManager.BuildInstallCommand("gsettings-desktop-schemas", false)

	if cr != nil {
		cr.outputChan <- fmt.Sprintf("Running: sudo %s", strings.Join(installCmd, " "))
	}
	return cr.RunSudoCommand(installCmd[0], installCmd[1:]...)
}

func (li *LinuxInstaller) ConfigureCelluloidPackageWithOutput(cr *CommandRunner) error {
	cr.outputChan <- "Configuring Celluloid settings..."
	cr.outputChan <- strings.Repeat("─", 50)

	if err := li.EnsureGSettingsInstalled(cr); err != nil {
		cr.outputChan <- "Warning: Failed to install gsettings, skipping configuration"
		return nil
	}

	cr.outputChan <- "Setting mpv-config-enable to true..."
	cmd := cr.RunCommand("gsettings", "set",
		"io.github.celluloid-player.Celluloid",
		"mpv-config-enable", "true")
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set gsettings (Celluloid may not be running)"
	}

	homeDir, _ := os.UserHomeDir()
	configDir := GetMPVConfigDirFromHome(homeDir)
	configPath := filepath.Join(configDir, "mpv.conf")
	cr.outputChan <- fmt.Sprintf("Setting mpv-config-file to: %s", configPath)
	cmd = cr.RunCommand("gsettings", "set",
		"io.github.celluloid-player.Celluloid",
		"mpv-config-file", configPath)
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set gsettings (Celluloid may not be running)"
	}

	cr.outputChan <- "Celluloid configuration set!"

	if err := li.Installer.DisableOSCForCelluloid(cr); err != nil {
		cr.outputChan <- fmt.Sprintf("Warning: Failed to disable OSC: %v", err)
	}

	return nil
}

func (li *LinuxInstaller) ConfigureCelluloidFlatpakWithOutput(cr *CommandRunner) error {
	cr.outputChan <- "Configuring Celluloid Flatpak..."
	cr.outputChan <- strings.Repeat("─", 50)

	cr.outputChan <- "Granting filesystem access to mpv config..."
	cmd := cr.RunCommand("flatpak", "override", "--user",
		"--filesystem=xdg-config/mpv:ro", constants.FlatpakCelluloid)
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set flatpak mpv dir override"
	}

	cr.outputChan <- "Setting mpv-config-enable to true..."
	cmd = cr.RunCommand("flatpak", "run", "--command=gsettings",
		constants.FlatpakCelluloid, "set",
		constants.GSettingsCelluloidSchema,
		"mpv-config-enable", "true")
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set gsettings mpv config true to flatpak"
	}

	homeDir, _ := os.UserHomeDir()
	configDir := GetMPVConfigDirFromHome(homeDir)
	configPath := filepath.Join(configDir, "mpv.conf")
	cr.outputChan <- fmt.Sprintf("Setting mpv-config-file to: %s", configPath)
	cmd = cr.RunCommand("flatpak", "run", "--command=gsettings",
		constants.FlatpakCelluloid, "set",
		constants.GSettingsCelluloidSchema,
		"mpv-config-file", configPath)
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set gsettings mpv file path to flatpak"
	}

	cr.outputChan <- "Celluloid Flatpak configuration set!"

	if err := li.Installer.DisableOSCForCelluloid(cr); err != nil {
		cr.outputChan <- fmt.Sprintf("Warning: Failed to disable OSC: %v", err)
	}

	return nil
}

func (li *LinuxInstaller) ConfigureMPVFlatpakWithOutput(cr *CommandRunner) error {
	cr.outputChan <- "Configuring MPV Flatpak..."
	cr.outputChan <- strings.Repeat("─", 50)

	cr.outputChan <- "Granting filesystem access to mpv config..."
	cmd := cr.RunCommand("flatpak", "override", "--user",
		"--filesystem=xdg-config/mpv:ro", constants.FlatpakMPV)
	if err := cmd; err != nil {
		cr.outputChan <- "Warning: Failed to set flatpak override"
	}

	cr.outputChan <- "MPV Flatpak configuration set!"
	return nil
}

func (li *LinuxInstaller) InstallIINAWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("IINA is not supported on Linux")
}

func (li *LinuxInstaller) InstallMPCQTWithOutput(cr *CommandRunner, method string) error {
	return fmt.Errorf("MPC-QT is not supported on Linux")
}

func (li *LinuxInstaller) InstallMPVAppWithOutput(cr *CommandRunner, uiType string) error {
	return fmt.Errorf("MPV App is not supported on Linux")
}

func (li *LinuxInstaller) InstallMPVViaBrewWithOutput(cr *CommandRunner, uiType string, isUpdate bool) error {
	return fmt.Errorf("Homebrew is not supported on Linux")
}

func (li *LinuxInstaller) UninstallAppWithOutput(cr *CommandRunner, appName string) error {
	return fmt.Errorf("App uninstallation is not supported on Linux")
}

func (li *LinuxInstaller) UpdateMPVAppWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("MPV App update is not supported on Linux")
}

func (li *LinuxInstaller) SetupFileAssociationsWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("File associations are not supported on Linux")
}

func (li *LinuxInstaller) CreateInstallerShortcutWithOutput(cr *CommandRunner) error {
	cr.outputChan <- "Installer shortcut creation not needed on Linux"
	return nil
}

func (li *LinuxInstaller) CreateInstallerShortcutToBinaryWithOutput(cr *CommandRunner, binaryPath string) error {
	cr.outputChan <- "Installer shortcut creation not needed on Linux"
	return nil
}

// InstallIcon installs the icon to ~/.local/share/icons/hicolor/128x128/apps/
func (li *LinuxInstaller) InstallIcon(cr *CommandRunner) error {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return fmt.Errorf("failed to get home directory: %w", err)
	}

	// Use XDG icon theme directory structure
	iconThemeDir := filepath.Join(homeDir, constants.LinuxIconsDir, constants.LinuxIconThemeDir)
	if err := os.MkdirAll(iconThemeDir, 0755); err != nil {
		return fmt.Errorf("failed to create icon theme directory: %w", err)
	}

	iconPath := filepath.Join(iconThemeDir, constants.LinuxIconFileName)

	// Check if icon already exists
	if _, err := os.Stat(iconPath); err == nil {
		cr.outputChan <- "Icon already installed: " + iconPath
		return nil
	}

	cr.outputChan <- "Installing icon to " + iconThemeDir + "..."

	// Read icon from embedded assets
	iconData, err := assets.ReadPNGIcon()
	if err != nil {
		return fmt.Errorf("failed to read icon from assets: %w", err)
	}

	// Write icon to destination
	if err := os.WriteFile(iconPath, iconData, 0644); err != nil {
		return fmt.Errorf("failed to write icon file: %w", err)
	}

	cr.outputChan <- "✓ Icon installed: " + iconPath

	// Update icon cache for desktop environments to pick up the new icon
	if _, err := exec.LookPath("gtk-update-icon-cache"); err == nil {
		iconsBaseDir := filepath.Join(homeDir, constants.LinuxIconsDir)
		cmd := exec.Command("gtk-update-icon-cache", "--quiet", "--force", iconsBaseDir)
		if err := cmd.Run(); err != nil {
			// Non-critical error, just log it
			cr.outputChan <- "Note: Failed to update icon cache (non-critical)"
		} else {
			cr.outputChan <- "✓ Icon cache updated"
		}
	} else if _, err := exec.LookPath("update-icon-caches"); err == nil {
		// Alternative command for some distros
		iconsBaseDir := filepath.Join(homeDir, constants.LinuxIconsDir)
		cmd := exec.Command("update-icon-caches", iconsBaseDir)
		if err := cmd.Run(); err != nil {
			// Non-critical error, just log it
			cr.outputChan <- "Note: Failed to update icon cache (non-critical)"
		} else {
			cr.outputChan <- "✓ Icon cache updated"
		}
	}

	return nil
}

func CreateLinuxWebUIShortcutWithOutput(cr *CommandRunner) error {
	execPath, err := os.Executable()
	if err != nil {
		return fmt.Errorf("failed to get executable path: %w", err)
	}

	cr.outputChan <- "Setting up MPV Manager..."

	homeDir, err := os.UserHomeDir()
	if err != nil {
		return fmt.Errorf("failed to get home directory: %w", err)
	}

	// Create .config/mpv directory for the binary (standard MPV config location)
	// Target: ~/.config/mpv/mpv-manager (the binary itself, not a directory)
	targetDir := filepath.Join(homeDir, ".config", "mpv")
	targetBinPath := filepath.Join(targetDir, constants.AppName)

	// Create the target directory if it doesn't exist
	if err := os.MkdirAll(targetDir, 0755); err != nil {
		return fmt.Errorf("failed to create directory %s: %w", targetDir, err)
	}

	// Check if we need to copy the binary
	shouldCopy := false

	// Resolve symlinks to get the real path
	realExecPath, err := filepath.EvalSymlinks(execPath)
	if err != nil {
		realExecPath = execPath // fallback to original if resolution fails
	}

	realTargetPath, err := filepath.EvalSymlinks(targetBinPath)
	if err != nil {
		// Target doesn't exist, need to copy
		shouldCopy = true
		cr.outputChan <- "Installing MPV Manager to " + targetDir + "..."
	} else {
		// Target exists, check if it's the same as current binary
		if realExecPath != realTargetPath {
			// Different location - check if we should update
			shouldCopy = true
			cr.outputChan <- "Updating MPV Manager at " + targetDir + "..."
		} else {
			// Already installed in target location
			cr.outputChan <- "MPV Manager already installed at: " + targetBinPath
		}
	}

	// Copy the binary if needed
	if shouldCopy {
		// Read the current executable
		input, err := os.ReadFile(execPath)
		if err != nil {
			return fmt.Errorf("failed to read executable: %w", err)
		}

		// Write to target location
		if err := os.WriteFile(targetBinPath, input, 0755); err != nil {
			return fmt.Errorf("failed to copy executable to %s: %w", targetBinPath, err)
		}

		// Ensure executable permissions
		if err := os.Chmod(targetBinPath, 0755); err != nil {
			return fmt.Errorf("failed to set executable permissions: %w", err)
		}

		cr.outputChan <- "✓ MPV Manager installed to: " + targetBinPath

		// Save the bin path to config for future updates
		if err := config.SetManagerBinPath(targetBinPath); err != nil {
			cr.outputChan <- fmt.Sprintf("Warning: Failed to save bin path to config: %v", err)
		}
	}

	// Extract the Linux uninstall script to the config directory
	if err := assets.ExtractUninstallLinuxSh(targetDir); err != nil {
		cr.outputChan <- fmt.Sprintf("Warning: Failed to extract uninstall script: %v", err)
	} else {
		cr.outputChan <- "✓ Uninstall script installed: " + filepath.Join(targetDir, "uninstall-linux.sh")
	}

	// Install icon
	li := &LinuxInstaller{}
	if err := li.InstallIcon(cr); err != nil {
		cr.outputChan <- "Warning: Failed to install icon: " + err.Error()
	}

	// Build absolute icon path for .desktop file
	iconPath := filepath.Join(homeDir, constants.LinuxIconsDir, constants.LinuxIconThemeDir, constants.LinuxIconFileName)

	// Create .desktop file pointing to the installed binary
	desktopFilePath := filepath.Join(homeDir, ".local", "share", "applications", "mpv-manager.desktop")
	if err := os.MkdirAll(filepath.Dir(desktopFilePath), 0755); err != nil {
		return fmt.Errorf("failed to create applications directory: %w", err)
	}

	desktopFileContent := `[Desktop Entry]
Name=MPV Manager
GenericName=MPV Media Player Manager (Web UI)
Comment=Install and manage MPV media player via Web UI
Exec=` + targetBinPath + ` -m web
Icon=` + iconPath + `
Terminal=false
Type=Application
Categories=Utility;AudioVideo;
StartupNotify=true
Keywords=mpv;media;player;installer;
`

	if err := os.WriteFile(desktopFilePath, []byte(desktopFileContent), 0644); err != nil {
		return fmt.Errorf("failed to write desktop file: %w", err)
	}

	desktopDir := filepath.Join(homeDir, "Desktop")
	desktopShortcutPath := filepath.Join(desktopDir, "mpv-manager.desktop")
	if err := os.Symlink(desktopFilePath, desktopShortcutPath); err != nil {
		// Symlink may already exist, try to remove and recreate
		os.Remove(desktopShortcutPath)
		if err := os.Symlink(desktopFilePath, desktopShortcutPath); err != nil {
			cr.outputChan <- "Note: Desktop symlink not created (may need to create manually)"
		} else {
			cr.outputChan <- "✓ Desktop shortcut created: " + desktopShortcutPath
		}
	} else {
		cr.outputChan <- "✓ Desktop shortcut created: " + desktopShortcutPath
	}

	cr.outputChan <- "✓ Application entry created: " + desktopFilePath
	cr.outputChan <- "Note: You may need to log out and log back in for shortcuts to appear in your menu."

	return nil
}

func (li *LinuxInstaller) CreateWebUIShortcutWithOutput(cr *CommandRunner) error {
	return CreateLinuxWebUIShortcutWithOutput(cr)
}

func (li *LinuxInstaller) InstallMPVWithOutput(cr *CommandRunner, method string, uiType string) error {
	return fmt.Errorf("MPV binary installation is not supported on Linux (use Flatpak or package manager)")
}

func (li *LinuxInstaller) UpdateMPVWithOutput(cr *CommandRunner, method string) error {
	return fmt.Errorf("MPV binary update is not supported on Linux (use Flatpak or package manager)")
}

// RemoveFileAssociationsWithOutput is a no-op on Linux
func (li *LinuxInstaller) RemoveFileAssociationsWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("file associations are not supported on Linux")
}

// CreateMPVShortcut is a no-op on Linux (shortcuts are not needed)
func (li *LinuxInstaller) CreateMPVShortcut(cr *CommandRunner) error {
	return fmt.Errorf("MPV shortcuts are not supported on Linux")
}

// UninstallWithOutput is a no-op on Linux
func (li *LinuxInstaller) UninstallWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("MPV binary uninstall is not supported on Linux")
}

// UninstallMPCQTWithOutput is a no-op on Linux (MPC-QT is Windows-only)
func (li *LinuxInstaller) UninstallMPCQTWithOutput(cr *CommandRunner) error {
	return fmt.Errorf("MPC-QT uninstall is not supported on Linux")
}
