package cmd

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log/slog"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/pelletier/go-toml/v2"
	"github.com/spf13/cobra"
	"go.yaml.in/yaml/v3"

	"github.com/tidbcloud/AgentTeam/desktop/internal/daemon"
	"github.com/tidbcloud/AgentTeam/desktop/internal/installpath"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

// serviceOpts holds flags for the service subcommands.
var serviceOpts struct {
	format string
	user   bool
}

// serviceStatusInfo holds service status data for serialization.
type serviceStatusInfo struct {
	Service    string `json:"service"       yaml:"service"       toml:"Service"`
	Scope      string `json:"scope"         yaml:"scope"         toml:"Scope"`
	Installed  bool   `json:"installed"     yaml:"installed"     toml:"Installed"`
	Status     string `json:"status"        yaml:"status"        toml:"Status"`
	PID        int    `json:"pid"           yaml:"pid"           toml:"PID"`
	Healthy    bool   `json:"healthy"        yaml:"healthy"       toml:"Healthy"`
	BaseURL    string `json:"base_url"       yaml:"base_url"       toml:"BaseURL,omitempty"`
	InstanceID string `json:"instance_id"    yaml:"instance_id"    toml:"InstanceID,omitempty"`
	APIVersion int    `json:"api_version"    yaml:"api_version"    toml:"APIVersion,omitempty"`
	OwnerKind  string `json:"owner_kind"     yaml:"owner_kind"     toml:"OwnerKind,omitempty"`
}

type serviceStatusReport struct {
	Services []serviceStatusInfo `json:"services" yaml:"services" toml:"Services"`
}

var (
	newServiceInstaller = daemon.NewInstaller
	currentDaemonStatus = daemon.NewStatus
	// Use ForceEnsureManagedBinary for service commands so that the binary the
	// user is currently running always becomes the managed service binary, even
	// when its version is lower than the one already installed at $HOME/.agentteam/bin/agentteam.
	// The non-force variant (EnsureManagedBinary) gates on version comparison,
	// which is correct for automatic upgrades but wrong when the user explicitly
	// runs `agentteam service install/reinstall/restart`.
	ensureServiceManagedBinary = installpath.ForceEnsureManagedBinary
	managedStatusBinaryPath    = installpath.ManagedBinaryPath
)

// serviceCmd manages the agentteam system service lifecycle.
var serviceCmd = &cobra.Command{
	Use:   "service",
	Short: "Manage the agentteam system service",
	Long: `Manage the agentteam system service lifecycle.

Install agentteam as a platform-native service (launchd on macOS, systemd on Linux,
Windows Service on Windows). System services auto-start on boot. On Linux,
--user installs a user-level systemd unit that starts with the user's systemd manager,
or on boot if lingering is enabled.

On macOS, launchd manages the service lifecycle automatically (RunAtLoad + KeepAlive),
so only install, uninstall, and restart are available under agentteam service.

On Linux and Windows, start/stop/restart commands are also available.

Examples:
  agentteam service install        Install as a system service
  agentteam service install --user Install as a user-level systemd service on Linux
  agentteam service uninstall      Remove the system service
  agentteam service restart        Restart the service
  agentteam status                 View current service status
  agentteam status --user          View current user-level systemd service status on Linux`,
}

// serviceInstallCmd installs agentteam as a system service for auto-start on boot.
var serviceInstallCmd = &cobra.Command{
	Use:   "install",
	Short: "Install agentteam as a system service",
	Long: `Install agentteam as a platform-native service.

On macOS this creates a launchd agent, on Linux a systemd unit,
and on Windows a Windows Service.
System services auto-start on boot. On Linux, --user installs a
user-level systemd unit that starts with the user's systemd manager;
enable lingering if you need it to start before login.

Examples:
  agentteam service install              Install with system tray (macOS/Windows)
  agentteam service install --user       Install as a user-level systemd service on Linux`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		exe, err := os.Executable()
		if err != nil {
			return fmt.Errorf("failed to determine executable path: %w", err)
		}
		managedExe, err := ensureServiceManagedBinary(exe)
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service install: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := daemon.NewInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		slog.Info("Installing agentteam service", "service", installer.Name(), "scope", scope)

		if err := installer.Install(daemon.InstallOptions{BinPath: managedExe, ConfigPath: configPath, Start: installStartsService(runtime.GOOS)}); err != nil {
			return err
		}

		slog.Info("agentteam service installed successfully", "service", installer.Name(), "scope", scope, "binary", managedExe)

		if runtime.GOOS != "darwin" {
			slog.Info("Use this command to start the service now", "command", startCommandHint(scope))
		}

		return nil
	},
}

// serviceUninstallCmd removes the agentteam system service from the current platform.
var serviceUninstallCmd = &cobra.Command{
	Use:   "uninstall",
	Short: "Remove the agentteam system service",
	Long: `Remove the agentteam system service from the current platform.

The daemon process will be stopped before removal.

	Examples:
  agentteam service uninstall        Remove the system service`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		managedExe, err := installpath.EnsureManagedBinaryFromCurrent()
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service uninstall: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := daemon.NewInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		slog.Info("Uninstalling agentteam service", "service", installer.Name(), "scope", scope)

		if err := installer.Uninstall(); err != nil {
			return err
		}

		slog.Info("agentteam service uninstalled successfully")
		return nil
	},
}

// serviceStartCmd starts the previously installed agentteam system service.
var serviceStartCmd = &cobra.Command{
	Use:   "start",
	Short: "Start the agentteam service",
	Long: `Start the agentteam system service. The service must be installed first.

	Examples:
  agentteam service start            Start the service`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		managedExe, err := installpath.EnsureManagedBinaryFromCurrent()
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service start: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := daemon.NewInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		if installer.IsInstalled() {
			if err := installer.Start(); err != nil {
				return err
			}
			slog.Info("agentteam service started", "service", installer.Name(), "scope", scope)
			return nil
		}

		slog.Info("agentteam service is not installed", "hint", fmt.Sprintf("Use '%s' to install it first", installCommandHint(scope)))
		return nil
	},
}

// serviceStopCmd stops the running agentteam system service.
var serviceStopCmd = &cobra.Command{
	Use:   "stop",
	Short: "Stop the agentteam service",
	Long: `Stop the running agentteam system service.

	Examples:
  agentteam service stop             Stop the service`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		managedExe, err := installpath.EnsureManagedBinaryFromCurrent()
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service stop: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := daemon.NewInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		if installer.IsInstalled() {
			if err := installer.Stop(); err != nil {
				return err
			}
			slog.Info("agentteam service stopped", "service", installer.Name(), "scope", scope)
			return nil
		}

		slog.Info("agentteam service is not installed")
		return nil
	},
}

// serviceRestartCmd restarts the agentteam system service without rewriting its service registration.
var serviceRestartCmd = &cobra.Command{
	Use:   "restart",
	Short: "Restart the agentteam service",
	Long: `Restart the agentteam system service without reinstalling or rewriting service configuration.

Use reinstall instead when service configuration changes, for example log
paths, PATH, or service arguments.

Examples:
  agentteam service restart          Restart the service after replacing the managed binary`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		exe, err := os.Executable()
		if err != nil {
			return fmt.Errorf("failed to determine executable path: %w", err)
		}
		managedExe, err := ensureServiceManagedBinary(exe)
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service restart: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := newServiceInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		if !installer.IsInstalled() {
			slog.Info("agentteam service is not installed", "hint", fmt.Sprintf("Use '%s' to install it first", installCommandHint(scope)))
			return nil
		}

		if err := installer.Restart(); err != nil {
			return err
		}

		slog.Info("agentteam service restarted", "service", installer.Name(), "scope", scope)
		return nil
	},
}

// serviceReinstallCmd uninstalls and then reinstalls the agentteam system service.
var serviceReinstallCmd = &cobra.Command{
	Use:   "reinstall",
	Short: "Reinstall the agentteam service",
	Long: `Uninstall and then reinstall the agentteam system service.
This picks up any changes to the service configuration (e.g., log paths).
If the service was running before reinstall, agentteam restores it to the running state after reinstall.

Examples:
  agentteam service reinstall              Reinstall with system tray (macOS/Windows)
  agentteam service reinstall --user       Reinstall as a user-level systemd service on Linux`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := ensureServicePrivileges(cmd); err != nil {
			return err
		}

		exe, err := os.Executable()
		if err != nil {
			return fmt.Errorf("failed to determine executable path: %w", err)
		}
		managedExe, err := ensureServiceManagedBinary(exe)
		if err != nil {
			return fmt.Errorf("prepare managed agentteam binary for service reinstall: %w", err)
		}

		scope := selectedServiceScope()
		configPath := selectedServiceConfigPath(scope)
		installer, err := newServiceInstaller(managedExe, configPath, scope)
		if err != nil {
			return err
		}

		wasInstalled := installer.IsInstalled()
		wasRunning := false
		if wasInstalled {
			status, err := installer.Status()
			if err != nil {
				return fmt.Errorf("failed to get current service status: %w", err)
			}
			wasRunning = isRunningServiceStatus(status)

			slog.Info("Uninstalling existing agentteam service...", "service", installer.Name(), "scope", scope)
			if err := installer.Uninstall(); err != nil {
				return err
			}
		}

		slog.Info("Reinstalling agentteam service...", "service", installer.Name(), "scope", scope)
		startAfterInstall := reinstallStartsService(runtime.GOOS, wasInstalled, wasRunning)
		if err := installer.Install(daemon.InstallOptions{BinPath: managedExe, ConfigPath: configPath, Start: startAfterInstall}); err != nil {
			return err
		}

		slog.Info("agentteam service reinstalled successfully", "service", installer.Name(), "scope", scope, "binary", managedExe)

		if runtime.GOOS != "darwin" {
			if wasRunning {
				slog.Info("agentteam service restored to running state", "service", installer.Name(), "scope", scope)
			} else {
				slog.Info("Use this command to start the service now", "command", startCommandHint(scope))
			}
		}

		return nil
	},
}

// statusCmd displays the current status of the agentteam system service.
var statusCmd = &cobra.Command{
	Use:   "status",
	Short: "Show agentteam service status",
	Long: `Display the current status of installed or running agentteam services.

On Linux, agentteam status checks both the system and user systemd managers by
default. Installed services are shown even when they are inactive or failed.
Use --user to limit the output to the current user's systemd manager.

Use --format/-f to control the output format.

Examples:
  agentteam status          Show service status in table format (default)
  agentteam status --user   Show only the user-level systemd service on Linux
  agentteam status -f json  Show status as JSON
  agentteam status --format yaml  Show status as YAML`,
	RunE: runServiceStatus,
}

func runServiceStatus(cmd *cobra.Command, args []string) error {
	managedExe := managedStatusBinaryPath()
	scope := selectedServiceScope()
	report, err := collectServiceStatusReport(runtime.GOOS, serviceOpts.user, managedExe, selectedServiceConfigPath(scope))
	if err != nil {
		return err
	}

	switch strings.ToLower(serviceOpts.format) {
	case "table":
		return printServiceStatusTable(report)
	case "json":
		return printServiceStatusJSON(report, false)
	case "jsonc":
		return printServiceStatusJSON(report, true)
	case "yaml":
		return printServiceStatusYAML(report)
	case "toml":
		return printServiceStatusTOML(report)
	default:
		return fmt.Errorf("unsupported format: %s (valid: table, json, jsonc, yaml, toml)", serviceOpts.format)
	}
}

func collectServiceStatusReport(goos string, userSelected bool, managedExe, configPath string) (serviceStatusReport, error) {
	scopes := statusScopes(goos, userSelected)
	report := serviceStatusReport{Services: make([]serviceStatusInfo, 0, len(scopes))}
	daemonStatus := currentDaemonStatus()
	if daemonStatus == nil {
		daemonStatus = &daemon.Status{}
	}

	for _, scope := range scopes {
		installer, err := newServiceInstaller(managedExe, configPath, scope)
		if err != nil {
			return serviceStatusReport{}, err
		}
		if !installer.IsInstalled() {
			continue
		}

		status, err := installer.Status()
		if err != nil {
			return serviceStatusReport{}, fmt.Errorf("failed to get %s service status: %w", scope, err)
		}
		status = displayServiceStatus(status)

		info := serviceStatusInfo{
			Service:   installer.Name(),
			Scope:     string(scope),
			Installed: true,
			Status:    status,
		}

		if isRunningServiceStatus(status) {
			addDaemonStatus(&info, daemonStatus)
		}

		report.Services = append(report.Services, info)
	}

	if !userSelected && daemonStatus.Running && !hasRunningInstalledService(report) {
		info := serviceStatusInfo{
			Service:   "agentteam-daemon",
			Scope:     "local",
			Installed: false,
			Status:    "active",
		}
		addDaemonStatus(&info, daemonStatus)
		report.Services = append(report.Services, info)
	}

	return report, nil
}

func addDaemonStatus(info *serviceStatusInfo, status *daemon.Status) {
	if status == nil || !status.Running {
		return
	}
	info.PID = status.PID
	info.Healthy = status.Healthy
	info.BaseURL = status.BaseURL
	info.InstanceID = status.InstanceID
	info.APIVersion = status.DesktopAPIVersion
	info.OwnerKind = string(status.OwnerKind)
}

func statusScopes(goos string, userSelected bool) []daemon.ServiceScope {
	if goos == "linux" {
		if userSelected {
			return []daemon.ServiceScope{daemon.ServiceScopeUser}
		}
		return []daemon.ServiceScope{daemon.ServiceScopeSystem, daemon.ServiceScopeUser}
	}
	if goos == "darwin" {
		return []daemon.ServiceScope{daemon.ServiceScopeUser}
	}
	return []daemon.ServiceScope{daemon.ServiceScopeSystem}
}

func isRunningServiceStatus(status string) bool {
	normalized := strings.ToLower(strings.TrimSpace(status))
	return normalized == "active" || normalized == "running"
}

func displayServiceStatus(status string) string {
	trimmed := strings.TrimSpace(status)
	if trimmed == "" {
		return "unknown"
	}
	return trimmed
}

func hasRunningInstalledService(report serviceStatusReport) bool {
	for _, info := range report.Services {
		if info.Installed && isRunningServiceStatus(info.Status) {
			return true
		}
	}
	return false
}

var journalOpts struct {
	tail   int
	head   int
	follow bool
}

var journalCmd = &cobra.Command{
	Use:   "journal",
	Short: "View agentteam service logs",
	Long: `View agentteam service log output.

Without any flags, displays help information including the default log path.

Examples:
  agentteam journal              Show help with default log path
  agentteam journal --tail 50    Show the last 50 lines
  agentteam journal --head 20    Show the first 20 lines
  agentteam journal -f           Follow log output in real time`,
	RunE: func(cmd *cobra.Command, args []string) error {
		cfg, err := profile.Load(profile.Path())
		if err != nil {
			return fmt.Errorf("failed to load config: %w", err)
		}

		logPath := cfg.LogFile()

		if !journalOpts.follow && journalOpts.tail == 0 && journalOpts.head == 0 {
			fmt.Fprintf(cmd.OutOrStdout(), "agentteam journal\n\n")
			fmt.Fprintf(cmd.OutOrStdout(), "Default log path: %s\n\n", logPath)
			fmt.Fprintf(cmd.OutOrStdout(), "Usage:\n")
			fmt.Fprintf(cmd.OutOrStdout(), "  agentteam journal --tail N    Show the last N lines\n")
			fmt.Fprintf(cmd.OutOrStdout(), "  agentteam journal --head N    Show the first N lines\n")
			fmt.Fprintf(cmd.OutOrStdout(), "  agentteam journal -f           Follow log output in real time\n")
			fmt.Fprintf(cmd.OutOrStdout(), "  agentteam journal -f --tail N  Follow from the last N lines\n")
			return nil
		}

		if _, err := os.Stat(logPath); os.IsNotExist(err) {
			return fmt.Errorf("log file not found: %s", logPath)
		}

		if journalOpts.follow {
			return followLog(cmd, logPath, journalOpts.tail)
		}

		f, err := os.Open(logPath)
		if err != nil {
			return fmt.Errorf("failed to open log file: %w", err)
		}
		defer f.Close()

		var scanner *bufio.Scanner
		if journalOpts.tail > 0 {
			lines, err := readTailLines(f, journalOpts.tail)
			if err != nil {
				return err
			}
			for _, line := range lines {
				fmt.Fprintln(cmd.OutOrStdout(), line)
			}
			return nil
		}

		if journalOpts.head > 0 {
			scanner = bufio.NewScanner(f)
			count := 0
			for scanner.Scan() && count < journalOpts.head {
				fmt.Fprintln(cmd.OutOrStdout(), scanner.Text())
				count++
			}
			return scanner.Err()
		}

		return nil
	},
}

func init() {
	statusCmd.Flags().StringVarP(&serviceOpts.format, "format", "f", "table", "output format (table|json|jsonc|yaml|toml)")
	if runtime.GOOS == "linux" {
		registerLinuxUserServiceFlag(serviceInstallCmd)
		registerLinuxUserServiceFlag(serviceUninstallCmd)
		registerLinuxUserServiceFlag(serviceRestartCmd)
		registerLinuxUserServiceFlag(serviceReinstallCmd)
		registerLinuxUserServiceFlag(statusCmd)
		registerLinuxUserServiceFlag(serviceStartCmd)
		registerLinuxUserServiceFlag(serviceStopCmd)
	}

	// start/stop are not available on macOS — launchd manages lifecycle automatically.
	if runtime.GOOS != "darwin" {
		serviceCmd.AddCommand(serviceStartCmd)
		serviceCmd.AddCommand(serviceStopCmd)
	}

	serviceCmd.AddCommand(serviceRestartCmd)
	serviceCmd.AddCommand(serviceReinstallCmd)
	serviceCmd.AddCommand(serviceInstallCmd)
	serviceCmd.AddCommand(serviceUninstallCmd)

	journalCmd.Aliases = []string{"j"}
	journalCmd.Flags().IntVar(&journalOpts.tail, "tail", 0, "show the last N lines")
	journalCmd.Flags().IntVar(&journalOpts.head, "head", 0, "show the first N lines")
	journalCmd.Flags().BoolVarP(&journalOpts.follow, "follow", "f", false, "follow log output in real time")
}

func printServiceStatusTable(report serviceStatusReport) error {
	if len(report.Services) == 0 {
		return nil
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	for i, info := range report.Services {
		if i > 0 {
			fmt.Fprintln(w)
		}
		fmt.Fprintf(w, "Service\t%s\n", info.Service)
		fmt.Fprintf(w, "Scope\t%s\n", info.Scope)
		fmt.Fprintf(w, "Installed\t%v\n", info.Installed)
		fmt.Fprintf(w, "Status\t%s\n", info.Status)
		if info.PID > 0 {
			fmt.Fprintf(w, "PID\t%d\n", info.PID)
		}
		fmt.Fprintf(w, "Healthy\t%v\n", info.Healthy)
		if info.BaseURL != "" {
			fmt.Fprintf(w, "Base URL\t%s\n", info.BaseURL)
		}
		if info.InstanceID != "" {
			fmt.Fprintf(w, "Instance\t%s\n", info.InstanceID)
		}
		if info.APIVersion > 0 {
			fmt.Fprintf(w, "Desktop API\t%d\n", info.APIVersion)
		}
		if info.OwnerKind != "" {
			fmt.Fprintf(w, "Owner\t%s\n", info.OwnerKind)
		}
	}
	return w.Flush()
}

func registerLinuxUserServiceFlag(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&serviceOpts.user, "user", false, "use the current user's systemd manager instead of the system manager")
}

func selectedServiceScope() daemon.ServiceScope {
	if runtime.GOOS == "linux" && serviceOpts.user {
		return daemon.ServiceScopeUser
	}
	if runtime.GOOS == "darwin" {
		return daemon.ServiceScopeUser
	}
	return daemon.ServiceScopeSystem
}

func installStartsService(goos string) bool {
	return goos == "darwin"
}

func reinstallStartsService(goos string, wasInstalled, wasRunning bool) bool {
	if wasRunning {
		return true
	}
	return goos == "darwin" && !wasInstalled
}

func selectedServiceConfigPath(scope daemon.ServiceScope) string {
	return serviceConfigPathFor(
		runtime.GOOS,
		scope,
		os.Geteuid(),
		os.Getenv("SUDO_USER"),
		os.Getenv(profile.ConfigDirEnvKey),
		profile.Path(),
		lookupUserHomeDir,
	)
}

func serviceConfigPathFor(
	goos string,
	scope daemon.ServiceScope,
	euid int,
	sudoUser string,
	configDirOverride string,
	defaultPath string,
	lookupHome func(string) (string, bool),
) string {
	if strings.TrimSpace(configDirOverride) != "" {
		return filepath.Join(configDirOverride, "config.yaml")
	}
	if goos != "linux" || scope != daemon.ServiceScopeSystem || euid != 0 {
		return defaultPath
	}
	sudoUser = strings.TrimSpace(sudoUser)
	if sudoUser == "" {
		return defaultPath
	}
	homeDir, ok := lookupHome(sudoUser)
	if !ok || strings.TrimSpace(homeDir) == "" {
		return defaultPath
	}
	return filepath.Join(homeDir, "."+profile.AppName, "config.yaml")
}

func lookupUserHomeDir(username string) (string, bool) {
	usr, err := user.Lookup(username)
	if err != nil || usr.HomeDir == "" {
		return "", false
	}
	return usr.HomeDir, true
}

func installCommandHint(scope daemon.ServiceScope) string {
	return "agentteam service install" + serviceScopeFlagSuffix(scope)
}

func startCommandHint(scope daemon.ServiceScope) string {
	return "agentteam service start" + serviceScopeFlagSuffix(scope)
}

func statusCommandHint(scope daemon.ServiceScope) string {
	return "agentteam status" + serviceScopeFlagSuffix(scope)
}

func serviceScopeFlagSuffix(scope daemon.ServiceScope) string {
	if runtime.GOOS == "linux" && scope == daemon.ServiceScopeUser {
		return " --user"
	}
	return ""
}

func validateLinuxUserServiceInvocation(euid int, sudoUser string) error {
	if runtime.GOOS != "linux" || euid != 0 || strings.TrimSpace(sudoUser) == "" {
		return nil
	}
	return fmt.Errorf("--user targets the current user's systemd manager; run it without sudo")
}

func ensureServicePrivileges(cmd *cobra.Command) error {
	if selectedServiceScope() == daemon.ServiceScopeUser {
		return validateLinuxUserServiceInvocation(os.Geteuid(), os.Getenv("SUDO_USER"))
	}
	ensureRoot(cmd)
	return nil
}

func printServiceStatusJSON(report serviceStatusReport, pretty bool) error {
	var data []byte
	var err error
	if pretty {
		data, err = json.MarshalIndent(report, "", "  ")
	} else {
		data, err = json.Marshal(report)
	}
	if err != nil {
		return err
	}
	fmt.Println(string(data))
	return nil
}

func printServiceStatusYAML(report serviceStatusReport) error {
	data, err := yaml.Marshal(report)
	if err != nil {
		return err
	}
	fmt.Print(string(data))
	return nil
}

func printServiceStatusTOML(report serviceStatusReport) error {
	data, err := toml.Marshal(report)
	if err != nil {
		return err
	}
	fmt.Print(string(data))
	return nil
}

func readTailLines(f *os.File, n int) ([]string, error) {
	stat, err := f.Stat()
	if err != nil {
		return nil, err
	}

	size := stat.Size()
	if size == 0 {
		return nil, nil
	}

	buf := make([]byte, size)
	if _, err := f.ReadAt(buf, 0); err != nil {
		return nil, err
	}

	var lines []string
	lineStart := -1
	for i := len(buf) - 1; i >= 0; i-- {
		if buf[i] == '\n' {
			if lineStart >= 0 {
				lines = append(lines, string(buf[i+1:lineStart]))
				if len(lines) >= n {
					break
				}
			}
			lineStart = i
		}
	}
	if lineStart >= 0 && len(lines) < n {
		lines = append(lines, string(buf[:lineStart]))
	}

	for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 {
		lines[i], lines[j] = lines[j], lines[i]
	}

	return lines, nil
}

func followLog(cmd *cobra.Command, logPath string, tailN int) error {
	f, err := os.Open(logPath)
	if err != nil {
		return fmt.Errorf("failed to open log file: %w", err)
	}
	defer f.Close()

	if tailN > 0 {
		lines, err := readTailLines(f, tailN)
		if err != nil {
			return err
		}
		for _, line := range lines {
			fmt.Fprintln(cmd.OutOrStdout(), line)
		}
	} else {
		if _, err := f.Seek(0, 2); err != nil {
			return err
		}
	}

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	ticker := time.NewTicker(300 * time.Millisecond)
	defer ticker.Stop()
	initial := time.NewTimer(500 * time.Millisecond)
	defer initial.Stop()

	reader := bufio.NewReader(f)
	for {
		select {
		case <-sigCh:
			return nil
		case <-initial.C:
		case <-ticker.C:
		}
		for {
			line, err := reader.ReadString('\n')
			if err != nil {
				break
			}
			fmt.Fprint(cmd.OutOrStdout(), line)
		}
	}
}
