// SPDX-License-Identifier: GPL-3.0-or-later

// Package cli provides the service command for managing the backend
// as a system service (systemd, launchd, OpenRC, Windows).
package cli

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
)

// newServiceCommand creates the service command group.
func (c *CLI) newServiceCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "service",
		Short: "Manage the backend system service",
		Long: `Install, remove, and control the Private Archive backend as a system service.

When installed as a service, the backend starts automatically on boot (or login
for user-level services) and restarts if it crashes. This is the recommended way
to run the backend for unattended backups.

Supported init systems:
  - systemd  (most Linux distributions)
  - OpenRC   (Alpine Linux, Gentoo)
  - launchd  (macOS)
  - Windows  (Task Scheduler / Windows Service)

The init system is detected automatically.`,
		Example: `  # Install as user service (no root required)
  privatebackup service install

  # Install as system service (requires root/admin)
  sudo privatebackup service install --system

  # Check if the service is installed and running
  privatebackup service status

  # Uninstall the service
  privatebackup service uninstall`,
	}

	cmd.AddCommand(c.newServiceInstallCommand())
	cmd.AddCommand(c.newServiceUninstallCommand())
	cmd.AddCommand(c.newServiceStartCommand())
	cmd.AddCommand(c.newServiceStopCommand())
	cmd.AddCommand(c.newServiceRestartCommand())
	cmd.AddCommand(c.newServiceStatusCommand())

	return cmd
}

// newServiceInstallCommand creates the service install subcommand.
func (c *CLI) newServiceInstallCommand() *cobra.Command {
	var systemLevel bool

	cmd := &cobra.Command{
		Use:   "install",
		Short: "Install the backend as a system service",
		Long: `Install the Private Archive backend as a persistent system service.

By default, installs as a user-level service that does not require root
or administrator privileges. Use --system to install system-wide.

User-level services:
  - systemd: runs via systemd --user with loginctl linger enabled
  - launchd: installs as a LaunchAgent in ~/Library/LaunchAgents
  - Windows: creates a Task Scheduler task that runs at logon

System-level services (--system, requires root/admin):
  - systemd: installs in /etc/systemd/system/
  - launchd: installs in /Library/LaunchDaemons/
  - OpenRC:  installs in /etc/init.d/
  - Windows: registers as a Windows Service`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("install", systemLevel)
		},
	}

	cmd.Flags().BoolVar(&systemLevel, "system", false, "Install as system-level service (requires root/admin)")

	return cmd
}

// newServiceUninstallCommand creates the service uninstall subcommand.
func (c *CLI) newServiceUninstallCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "uninstall",
		Short: "Remove the backend system service",
		Long: `Stop, disable, and remove the Private Archive backend service.

This does not remove the backend binary, configuration, or backup data.
Only the service registration is removed.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("uninstall", false)
		},
	}
}

// newServiceStartCommand creates the service start subcommand.
func (c *CLI) newServiceStartCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "start",
		Short: "Start the backend service",
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("start", false)
		},
	}
}

// newServiceStopCommand creates the service stop subcommand.
func (c *CLI) newServiceStopCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "stop",
		Short: "Stop the backend service",
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("stop", false)
		},
	}
}

// newServiceRestartCommand creates the service restart subcommand.
func (c *CLI) newServiceRestartCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "restart",
		Short: "Restart the backend service",
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("restart", false)
		},
	}
}

// newServiceStatusCommand creates the service status subcommand.
func (c *CLI) newServiceStatusCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "status",
		Short: "Show backend service status",
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runServiceAction("status", false)
		},
	}
}

// runServiceAction delegates a service operation to the backend binary.
func (c *CLI) runServiceAction(action string, systemLevel bool) error {
	backendBin := c.findBackendBinary()
	if backendBin == "" {
		c.renderer.Error("Backend binary not found")
		c.renderer.Info("Ensure privatebackup-backend is installed and in your PATH.")
		c.renderer.Info("Install locations: /usr/local/bin/, /usr/bin/, or in the same directory as this CLI.")
		return fmt.Errorf("privatebackup-backend not found")
	}

	args := []string{"service", action}
	if systemLevel {
		args = append(args, "--system")
	}

	cmd := exec.Command(backendBin, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			return fmt.Errorf("service %s failed (exit code %d)", action, exitErr.ExitCode())
		}
		return fmt.Errorf("service %s failed: %w", action, err)
	}

	return nil
}
