// Package hostproxy provides the hidden host-proxy command group for daemon management.
package hostproxy

import (
	"context"
	"fmt"
	"time"

	"github.com/schmitthub/clawker/internal/config"
	"github.com/schmitthub/clawker/internal/hostproxy"
	"github.com/schmitthub/clawker/internal/logger"
	"github.com/spf13/cobra"
)

// NewCmdServe creates the hidden daemon subcommand that runs the host proxy server.
// This is invoked by Manager.EnsureRunning() when spawning a daemon subprocess.
func NewCmdServe() *cobra.Command {
	var (
		port         int
		pollInterval time.Duration
		gracePeriod  time.Duration
	)

	cmd := &cobra.Command{
		Use:    "serve",
		Short:  "Run the host proxy server as a daemon",
		Long:   "Internal command to run the host proxy server as a background daemon process.",
		Hidden: true,
		Example: `  # Start the host proxy daemon (internal use only)
  clawker host-proxy serve
  clawker host-proxy serve --port 18374
  clawker host-proxy serve --grace-period 2m`,
		RunE: func(cmd *cobra.Command, args []string) error {
			cfg, err := config.NewConfig()
			if err != nil {
				return fmt.Errorf("failed to load config: %w", err)
			}

			// Create a dedicated logger that writes to hostproxy.log,
			// not the shared clawker.log. Falls back to nop if unavailable.
			log := logger.Nop()
			if logsDir, dirErr := cfg.LogsSubdir(); dirErr == nil {
				if l, lErr := logger.New(logger.Options{LogsDir: logsDir, Filename: "hostproxy.log"}); lErr == nil {
					log = l
					defer l.Close()
				}
			}

			// Collect flag overrides — these take precedence over config values
			// without mutating the config object.
			var opts []hostproxy.DaemonOption
			if cmd.Flags().Changed("port") {
				opts = append(opts, hostproxy.WithDaemonPort(port))
			}
			if cmd.Flags().Changed("poll-interval") {
				opts = append(opts, hostproxy.WithPollInterval(pollInterval))
			}
			if cmd.Flags().Changed("grace-period") {
				opts = append(opts, hostproxy.WithGracePeriod(gracePeriod))
			}

			daemon, err := hostproxy.NewDaemon(cfg, log, opts...)
			if err != nil {
				log.Error().Err(err).Msg("failed to create daemon")
				return err
			}

			ctx := context.Background()
			if err := daemon.Run(ctx); err != nil {
				log.Error().Err(err).Msg("daemon error")
				return err
			}

			log.Debug().Msg("host proxy daemon stopped")
			return nil
		},
	}

	cmd.Flags().IntVar(&port, "port", 18374, "Port to listen on")
	cmd.Flags().DurationVar(&pollInterval, "poll-interval", 30*time.Second, "Container poll interval")
	cmd.Flags().DurationVar(&gracePeriod, "grace-period", 60*time.Second, "Initial grace period before container checking")

	return cmd
}

// NewCmdHostProxy creates the hidden host-proxy command group.
func NewCmdHostProxy() *cobra.Command {
	cmd := &cobra.Command{
		Use:    "host-proxy",
		Short:  "Host proxy daemon management",
		Long:   "Internal commands for managing the host proxy daemon.",
		Hidden: true,
	}

	cmd.AddCommand(NewCmdServe())
	cmd.AddCommand(NewCmdStatus())
	cmd.AddCommand(NewCmdStop())

	return cmd
}

// NewCmdStatus creates a command to check daemon status.
func NewCmdStatus() *cobra.Command {
	return &cobra.Command{
		Use:    "status",
		Short:  "Check host proxy daemon status",
		Hidden: true,
		Example: `  # Check if the host proxy daemon is running
  clawker host-proxy status`,
		RunE: func(cmd *cobra.Command, args []string) error {
			cfg, err := config.NewConfig()
			if err != nil {
				return fmt.Errorf("failed to load config: %w", err)
			}
			pidFile, err := cfg.HostProxyPIDFilePath()
			if err != nil {
				return fmt.Errorf("failed to resolve PID file path: %w", err)
			}
			pid := hostproxy.GetDaemonPID(pidFile)
			if pid == 0 {
				cmd.Println("Host proxy daemon is not running")
				return nil
			}
			cmd.Printf("Host proxy daemon is running (PID: %d)\n", pid)
			return nil
		},
	}
}

// NewCmdStop creates a command to stop the daemon.
func NewCmdStop() *cobra.Command {
	var wait time.Duration

	cmd := &cobra.Command{
		Use:    "stop",
		Short:  "Stop the host proxy daemon",
		Hidden: true,
		Example: `  # Send stop signal to the daemon
  clawker host-proxy stop

  # Stop and wait up to 5 seconds for shutdown
  clawker host-proxy stop --wait 5s`,
		RunE: func(cmd *cobra.Command, args []string) error {
			cfg, err := config.NewConfig()
			if err != nil {
				return fmt.Errorf("failed to load config: %w", err)
			}
			pidFile, err := cfg.HostProxyPIDFilePath()
			if err != nil {
				return fmt.Errorf("failed to resolve PID file path: %w", err)
			}
			if err := hostproxy.StopDaemon(pidFile); err != nil {
				return err
			}
			cmd.Println("Stop signal sent to host proxy daemon")

			if wait > 0 {
				// Wait for daemon to stop
				deadline := time.Now().Add(wait)
				for time.Now().Before(deadline) {
					if !hostproxy.IsDaemonRunning(pidFile) {
						cmd.Println("Host proxy daemon stopped")
						return nil
					}
					time.Sleep(100 * time.Millisecond)
				}
				return fmt.Errorf("timeout waiting for daemon to stop after %v", wait)
			}
			return nil
		},
	}

	cmd.Flags().DurationVar(&wait, "wait", 0, "Wait for daemon to stop (0 = don't wait)")

	return cmd
}
