package cmd

import (
	"context"
	"fmt"
	"log/slog"

	"github.com/spf13/cobra"

	"github.com/tidbcloud/AgentTeam/desktop/internal/daemon"
	"github.com/tidbcloud/AgentTeam/desktop/internal/upgrade"
)

var upgradeOpts struct {
	checkOnly bool
}

var upgradeApplyOpts struct {
	version          string
	installScriptURL string
	checksumsURL     string
	archiveURL       string
	daemonPID        int
}

var upgradeCmd = &cobra.Command{
	Use:   "upgrade",
	Short: "Check for updates and upgrade the Linux agentteam daemon",
	Long: `Check the Linux daemon release manifest for a newer version of agentteam.
If a newer version is available, this command starts a background upgrade helper
that installs the target version and restarts the daemon if needed.

macOS and Windows application updates are installed by AgentTeam Desktop's Electron
updater; this Go self-updater is available only on Linux.

By default, this command launches the upgrade helper. Use --check to only
check for available updates without downloading or installing.

Examples:
  agentteam upgrade          Check and start upgrading if a newer version is available
  agentteam upgrade --check  Only check whether a newer version is available`,
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		if upgradeOpts.checkOnly {
			return runUpgradeCheck(ctx)
		}
		return runUpgrade(ctx)
	},
}

var upgradeApplyCmd = &cobra.Command{
	Use:    "apply",
	Hidden: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return upgrade.ApplyRelease(cmd.Context(), upgrade.ApplyOptions{
			Version:          upgradeApplyOpts.version,
			InstallScriptURL: upgradeApplyOpts.installScriptURL,
			ChecksumsURL:     upgradeApplyOpts.checksumsURL,
			ArchiveURL:       upgradeApplyOpts.archiveURL,
			DaemonPID:        upgradeApplyOpts.daemonPID,
		})
	},
}

func runUpgradeCheck(ctx context.Context) error {
	result, err := upgrade.CheckVersion(ctx, "")
	if err != nil {
		return err
	}

	slog.Info("current version", "version", result.Current)
	slog.Info("latest version", "version", result.Latest)

	if result.HasUpdate {
		slog.Info("a new version is available", "manifest", result.ManifestURL)
		slog.Info("run 'agentteam upgrade' to upgrade in the background")
	} else {
		slog.Info("agentteam is already up to date")
	}
	return nil
}

func runUpgrade(ctx context.Context) error {
	result, err := upgrade.CheckVersion(ctx, "")
	if err != nil {
		return err
	}
	if !result.HasUpdate {
		slog.Info("agentteam is already up to date", "version", result.Current)
		return nil
	}
	if !result.CanAutoUpgrade {
		switch result.UpdateMethod {
		case upgrade.UpdateMethodManualCommand:
			slog.Info("automatic upgrade is unavailable; run the manual command instead",
				"platform", result.Platform,
				"command", result.ManualCommand,
			)
			return nil
		default:
			return fmt.Errorf("automatic upgrade is not supported on %s", result.Platform)
		}
	}

	status := daemon.NewStatus()
	launch, err := upgrade.StartBackgroundUpgrade(upgrade.LaunchOptions{
		Version:          result.Latest,
		InstallScriptURL: result.InstallScriptURL,
		ChecksumsURL:     result.ChecksumsURL,
		ArchiveURL:       result.RuntimeAssetURL,
		DaemonPID:        status.PID,
	})
	if err != nil {
		return err
	}

	fmt.Printf("agentteam upgrade started in background: target=%s log=%s pid=%d\n", launch.Version, launch.LogPath, launch.PID)
	if status.Running {
		fmt.Println("the running daemon will restart after the new version is installed")
	}
	return nil
}

func init() {
	upgradeCmd.Flags().BoolVar(&upgradeOpts.checkOnly, "check", false, "only check for available updates, do not install")
	upgradeApplyCmd.Flags().StringVar(&upgradeApplyOpts.version, "version", "", "target version for internal upgrade helper")
	upgradeApplyCmd.Flags().StringVar(&upgradeApplyOpts.installScriptURL, "install-script-url", "", "install script URL for internal upgrade helper")
	upgradeApplyCmd.Flags().StringVar(&upgradeApplyOpts.checksumsURL, "checksums-url", "", "checksums URL for internal upgrade helper")
	upgradeApplyCmd.Flags().StringVar(&upgradeApplyOpts.archiveURL, "archive-url", "", "archive URL for internal upgrade helper")
	upgradeApplyCmd.Flags().IntVar(&upgradeApplyOpts.daemonPID, "daemon-pid", 0, "daemon pid for internal upgrade helper")
	upgradeCmd.AddCommand(upgradeApplyCmd)
}
