package installer

import (
	"fmt"
	"strings"

	"gitgud.io/mike/mpv-manager/pkg/constants"
)

// PackageManager handles package manager operations
type PackageManager struct {
	family string
	cmd    string
}

// NewPackageManager creates a new package manager instance
func NewPackageManager(family string) *PackageManager {
	var cmd string
	switch family {
	case constants.PMFamilyDebian:
		cmd = constants.CommandApt
	case constants.PMFamilyRHEL:
		cmd = constants.CommandDnf
	case constants.PMFamilyArch:
		cmd = constants.CommandPacman
	}
	return &PackageManager{family: family, cmd: cmd}
}

// BuildInstallCommand builds an install command with privilege prefix
func (pm *PackageManager) BuildInstallCommand(packageName string, withPrivilege bool) []string {
	cmds, ok := constants.PackageManagerConfigs[pm.cmd]
	if !ok {
		return nil
	}

	var result []string
	if withPrivilege {
		result = append(result, GetPrivilegePrefix()...)
	}

	result = append(result, cmds.Install...)
	result = append(result, packageName)

	return result
}

// BuildUpdateCommand builds a package update command with privilege prefix
func (pm *PackageManager) BuildUpdateCommand(withPrivilege bool) []string {
	cmds, ok := constants.PackageManagerConfigs[pm.cmd]
	if !ok {
		return nil
	}

	var result []string
	if withPrivilege {
		result = append(result, GetPrivilegePrefix()...)
	}

	result = append(result, cmds.Update...)

	return result
}

// BuildUpgradeCommand builds an upgrade command with privilege prefix
func (pm *PackageManager) BuildUpgradeCommand(packageName string, withPrivilege bool) []string {
	cmds, ok := constants.PackageManagerConfigs[pm.cmd]
	if !ok {
		return nil
	}

	var result []string
	if withPrivilege {
		result = append(result, GetPrivilegePrefix()...)
	}

	result = append(result, cmds.Upgrade...)
	if packageName != "" {
		result = append(result, packageName)
	}

	return result
}

// BuildRemoveCommand builds a remove command with privilege prefix
func (pm *PackageManager) BuildRemoveCommand(packageName string, withPrivilege bool) []string {
	cmds, ok := constants.PackageManagerConfigs[pm.cmd]
	if !ok {
		return nil
	}

	var result []string
	if withPrivilege {
		result = append(result, GetPrivilegePrefix()...)
	}

	result = append(result, cmds.Remove...)
	result = append(result, packageName)

	return result
}

// GetCommandName returns the base command name
func (pm *PackageManager) GetCommandName() string {
	return pm.cmd
}

// GetFamily returns the package manager family
func (pm *PackageManager) GetFamily() string {
	return pm.family
}

// FlatpakManager handles Flatpak operations
type FlatpakManager struct{}

// NewFlatpakManager creates a new Flatpak manager instance
func NewFlatpakManager() *FlatpakManager {
	return &FlatpakManager{}
}

// BuildInstallCommands builds Flatpak install commands (may return multiple commands)
func (fm *FlatpakManager) BuildInstallCommands(appID string, enableFlathub bool) [][]string {
	var commands [][]string

	if enableFlathub {
		commands = append(commands, constants.FlatpakCommands["add-remote"])
	}

	installCmd := append([]string{},
		constants.FlatpakCommands["install"]...)
	installCmd = append(installCmd, appID)
	commands = append(commands, installCmd)

	return commands
}

// BuildUpdateCommand builds a Flatpak update command
func (fm *FlatpakManager) BuildUpdateCommand(appID string) []string {
	updateCmd := append([]string{},
		constants.FlatpakCommands["update"]...)
	if appID != "" {
		updateCmd = append(updateCmd, appID)
	}
	return updateCmd
}

// BuildRemoveCommand builds a Flatpak remove command
func (fm *FlatpakManager) BuildRemoveCommand(appID string) []string {
	removeCmd := append([]string{},
		constants.FlatpakCommands["remove"]...)
	removeCmd = append(removeCmd, appID)
	return removeCmd
}

// BuildOverrideCommand builds a Flatpak override command
func (fm *FlatpakManager) BuildOverrideCommand(override string, appID string) []string {
	cmd := append([]string{},
		constants.FlatpakCommands["override"]...)
	cmd = append(cmd, override, appID)
	return cmd
}

// BuildGsettingsCommand builds a command to run gsettings in Flatpak
func (fm *FlatpakManager) BuildGsettingsCommand(appID, schema, key, value string) []string {
	return []string{
		"flatpak", "run", "--command=gsettings",
		appID, "set", schema, key, value,
	}
}

// ExecuteCommands executes multiple commands and returns combined error
func ExecuteCommands(cr *CommandRunner, commandSets [][]string) error {
	for i, cmdSet := range commandSets {
		if len(cmdSet) == 0 {
			continue
		}

		cmdStr := strings.Join(cmdSet, " ")

		if cr != nil {
			if len(commandSets) > 1 {
				cr.outputChan <- fmt.Sprintf("Step %d/%d: %s", i+1, len(commandSets), cmdStr)
			} else {
				cr.outputChan <- fmt.Sprintf("Running: %s", cmdStr)
			}
		}

		if err := cr.RunCommand(cmdSet[0], cmdSet[1:]...); err != nil {
			return err
		}
	}
	return nil
}

// ExecuteCommandsWithPrivilege executes commands with package manager support
func ExecuteCommandsWithPrivilege(cr *CommandRunner, family string, commandType, packageName string, enableFlathub bool) error {
	switch family {
	case constants.PMFamilyDebian, constants.PMFamilyRHEL, constants.PMFamilyArch:
		pm := NewPackageManager(family)
		var cmdSet []string

		withPrivilege := true
		switch commandType {
		case "install":
			cmdSet = pm.BuildInstallCommand(packageName, withPrivilege)
		case "update":
			cmdSet = pm.BuildUpdateCommand(withPrivilege)
		case "upgrade":
			cmdSet = pm.BuildUpgradeCommand(packageName, withPrivilege)
		case "remove":
			cmdSet = pm.BuildRemoveCommand(packageName, withPrivilege)
		}

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

	case "flatpak":
		fm := NewFlatpakManager()
		switch commandType {
		case "install":
			cmds := fm.BuildInstallCommands(packageName, enableFlathub)
			if cr != nil {
				for i, cmd := range cmds {
					if len(cmds) > 1 {
						cr.outputChan <- fmt.Sprintf("Step %d/%d: %s", i+1, len(cmds), strings.Join(cmd, " "))
					} else {
						cr.outputChan <- fmt.Sprintf("Running: %s", strings.Join(cmd, " "))
					}
				}
			}
			// Execute each command (might be multiple for install with flathub)
			for _, cmd := range cmds {
				if err := cr.RunCommand(cmd[0], cmd[1:]...); err != nil {
					return err
				}
			}
			return nil
		case "update":
			cmd := fm.BuildUpdateCommand(packageName)
			if cr != nil {
				cr.outputChan <- fmt.Sprintf("Running: %s", strings.Join(cmd, " "))
			}
			return cr.RunCommand(cmd[0], cmd[1:]...)
		case "remove":
			cmd := fm.BuildRemoveCommand(packageName)
			if cr != nil {
				cr.outputChan <- fmt.Sprintf("Running: %s", strings.Join(cmd, " "))
			}
			return cr.RunCommand(cmd[0], cmd[1:]...)
		}
	}

	return fmt.Errorf("unsupported package manager: %s", family)
}
