package cmd

import (
	"fmt"
	"os/exec"

	"github.com/spf13/cobra"
	"github.com/steveyegge/gastown/internal/beads"
	"github.com/steveyegge/gastown/internal/refinery"
	"github.com/steveyegge/gastown/internal/style"
	"github.com/steveyegge/gastown/internal/tmux"
	"github.com/steveyegge/gastown/internal/witness"
)

// RigDockedLabel is the label set on rig identity beads when docked.
const RigDockedLabel = "status:docked"

var rigDockCmd = &cobra.Command{
	Use:   "dock <rig>",
	Short: "Dock a rig (global, persistent shutdown)",
	Long: `Dock a rig to persistently disable it across all clones.

Docking a rig:
  - Stops the witness if running
  - Stops the refinery if running
  - Sets status:docked label on the rig identity bead
  - Syncs via git so all clones see the docked status

This is a Level 2 (global/persistent) operation:
  - Affects all clones of this rig (via git sync)
  - Persists until explicitly undocked
  - The daemon respects this status and won't auto-restart agents

Use 'gt rig undock' to resume normal operation.

Examples:
  gt rig dock gastown
  gt rig dock beads`,
	Args: cobra.ExactArgs(1),
	RunE: runRigDock,
}

var rigUndockCmd = &cobra.Command{
	Use:   "undock <rig>",
	Short: "Undock a rig (remove global docked status)",
	Long: `Undock a rig to remove the persistent docked status.

Undocking a rig:
  - Removes the status:docked label from the rig identity bead
  - Syncs via git so all clones see the undocked status
  - Allows the daemon to auto-restart agents
  - Does NOT automatically start agents (use 'gt rig start' for that)

Examples:
  gt rig undock gastown
  gt rig undock beads`,
	Args: cobra.ExactArgs(1),
	RunE: runRigUndock,
}

func init() {
	rigCmd.AddCommand(rigDockCmd)
	rigCmd.AddCommand(rigUndockCmd)
}

func runRigDock(cmd *cobra.Command, args []string) error {
	rigName := args[0]

	// Get rig
	_, r, err := getRig(rigName)
	if err != nil {
		return err
	}

	// Get rig prefix for bead ID
	prefix := "gt" // default
	if r.Config != nil && r.Config.Prefix != "" {
		prefix = r.Config.Prefix
	}

	// Find the rig identity bead
	rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)
	bd := beads.New(r.BeadsPath())

	// Check if rig bead exists, create if not
	rigBead, err := bd.Show(rigBeadID)
	if err != nil {
		// Rig identity bead doesn't exist (legacy rig) - create it
		fmt.Printf("  Creating rig identity bead %s...\n", rigBeadID)
		rigBead, err = bd.CreateRigBead(rigBeadID, rigName, &beads.RigFields{
			Repo:   r.GitURL,
			Prefix: prefix,
			State:  "active",
		})
		if err != nil {
			return fmt.Errorf("creating rig identity bead: %w", err)
		}
	}

	// Check if already docked
	for _, label := range rigBead.Labels {
		if label == RigDockedLabel {
			fmt.Printf("%s Rig %s is already docked\n", style.Dim.Render("•"), rigName)
			return nil
		}
	}

	fmt.Printf("Docking rig %s...\n", style.Bold.Render(rigName))

	var stoppedAgents []string

	t := tmux.NewTmux()

	// Stop witness if running
	witnessSession := fmt.Sprintf("gt-%s-witness", rigName)
	witnessRunning, _ := t.HasSession(witnessSession)
	if witnessRunning {
		fmt.Printf("  Stopping witness...\n")
		witMgr := witness.NewManager(r)
		if err := witMgr.Stop(); err != nil {
			fmt.Printf("  %s Failed to stop witness: %v\n", style.Warning.Render("!"), err)
		} else {
			stoppedAgents = append(stoppedAgents, "Witness stopped")
		}
	}

	// Stop refinery if running
	refinerySession := fmt.Sprintf("gt-%s-refinery", rigName)
	refineryRunning, _ := t.HasSession(refinerySession)
	if refineryRunning {
		fmt.Printf("  Stopping refinery...\n")
		refMgr := refinery.NewManager(r)
		if err := refMgr.Stop(); err != nil {
			fmt.Printf("  %s Failed to stop refinery: %v\n", style.Warning.Render("!"), err)
		} else {
			stoppedAgents = append(stoppedAgents, "Refinery stopped")
		}
	}

	// Set docked label on rig identity bead
	if err := bd.Update(rigBeadID, beads.UpdateOptions{
		AddLabels: []string{RigDockedLabel},
	}); err != nil {
		return fmt.Errorf("setting docked label: %w", err)
	}

	// Sync beads to propagate to other clones
	fmt.Printf("  Syncing beads...\n")
	syncCmd := exec.Command("bd", "sync")
	syncCmd.Dir = r.BeadsPath()
	if output, err := syncCmd.CombinedOutput(); err != nil {
		fmt.Printf("  %s bd sync warning: %v\n%s", style.Warning.Render("!"), err, string(output))
	}

	// Output
	fmt.Printf("%s Rig %s docked (global)\n", style.Success.Render("✓"), rigName)
	fmt.Printf("  Label added: %s\n", RigDockedLabel)
	for _, msg := range stoppedAgents {
		fmt.Printf("  %s\n", msg)
	}
	fmt.Printf("  Run '%s' to propagate to other clones\n", style.Dim.Render("bd sync"))

	return nil
}

func runRigUndock(cmd *cobra.Command, args []string) error {
	rigName := args[0]

	// Get rig and town root
	_, r, err := getRig(rigName)
	if err != nil {
		return err
	}

	// Get rig prefix for bead ID
	prefix := "gt" // default
	if r.Config != nil && r.Config.Prefix != "" {
		prefix = r.Config.Prefix
	}

	// Find the rig identity bead
	rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)
	bd := beads.New(r.BeadsPath())

	// Check if rig bead exists, create if not
	rigBead, err := bd.Show(rigBeadID)
	if err != nil {
		// Rig identity bead doesn't exist (legacy rig) - can't be docked
		fmt.Printf("%s Rig %s has no identity bead and is not docked\n", style.Dim.Render("•"), rigName)
		return nil
	}

	// Check if actually docked
	isDocked := false
	for _, label := range rigBead.Labels {
		if label == RigDockedLabel {
			isDocked = true
			break
		}
	}
	if !isDocked {
		fmt.Printf("%s Rig %s is not docked\n", style.Dim.Render("•"), rigName)
		return nil
	}

	// Remove docked label from rig identity bead
	if err := bd.Update(rigBeadID, beads.UpdateOptions{
		RemoveLabels: []string{RigDockedLabel},
	}); err != nil {
		return fmt.Errorf("removing docked label: %w", err)
	}

	// Sync beads to propagate to other clones
	fmt.Printf("  Syncing beads...\n")
	syncCmd := exec.Command("bd", "sync")
	syncCmd.Dir = r.BeadsPath()
	if output, err := syncCmd.CombinedOutput(); err != nil {
		fmt.Printf("  %s bd sync warning: %v\n%s", style.Warning.Render("!"), err, string(output))
	}

	fmt.Printf("%s Rig %s undocked\n", style.Success.Render("✓"), rigName)
	fmt.Printf("  Label removed: %s\n", RigDockedLabel)
	fmt.Printf("  Daemon can now auto-restart agents\n")
	fmt.Printf("  Use '%s' to start agents immediately\n", style.Dim.Render("gt rig start "+rigName))

	return nil
}

// IsRigDocked checks if a rig is docked by checking for the status:docked label
// on the rig identity bead. This function is exported for use by the daemon.
func IsRigDocked(townRoot, rigName, prefix string) bool {
	// Construct the rig beads path
	rigPath := townRoot + "/" + rigName
	beadsPath := rigPath + "/mayor/rig"
	if _, err := exec.Command("test", "-d", beadsPath).CombinedOutput(); err != nil {
		beadsPath = rigPath
	}

	bd := beads.New(beadsPath)
	rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)

	rigBead, err := bd.Show(rigBeadID)
	if err != nil {
		return false
	}

	for _, label := range rigBead.Labels {
		if label == RigDockedLabel {
			return true
		}
	}
	return false
}
