package cmd

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/spf13/cobra"
	"github.com/steveyegge/gastown/internal/config"
)

func TestDiscoverHooksSkipsPolecatDotDirs(t *testing.T) {
	townRoot := setupTestTownForDotDir(t)
	rigPath := filepath.Join(townRoot, "gastown")

	settingsPath := filepath.Join(rigPath, "polecats", ".claude", ".claude", "settings.json")
	if err := os.MkdirAll(filepath.Dir(settingsPath), 0755); err != nil {
		t.Fatalf("mkdir settings dir: %v", err)
	}

	settings := `{"hooks":{"SessionStart":[{"matcher":"*","hooks":[{"type":"Stop","command":"echo hi"}]}]}}`
	if err := os.WriteFile(settingsPath, []byte(settings), 0644); err != nil {
		t.Fatalf("write settings: %v", err)
	}

	hooks, err := discoverHooks(townRoot)
	if err != nil {
		t.Fatalf("discoverHooks: %v", err)
	}

	if len(hooks) != 0 {
		t.Fatalf("expected no hooks, got %d", len(hooks))
	}
}

func TestStartPolecatsWithWorkSkipsDotDirs(t *testing.T) {
	townRoot := setupTestTownForDotDir(t)
	rigName := "gastown"
	rigPath := filepath.Join(townRoot, rigName)

	addRigEntry(t, townRoot, rigName)

	if err := os.MkdirAll(filepath.Join(rigPath, "polecats", ".claude"), 0755); err != nil {
		t.Fatalf("mkdir .claude polecat: %v", err)
	}
	if err := os.MkdirAll(filepath.Join(rigPath, "polecats", "toast"), 0755); err != nil {
		t.Fatalf("mkdir polecat: %v", err)
	}

	binDir := t.TempDir()
	bdScript := `#!/bin/sh
if [ "$1" = "--no-daemon" ]; then
  shift
fi
cmd="$1"
case "$cmd" in
  list)
    if [ "$(basename "$PWD")" = ".claude" ]; then
      echo '[{"id":"gt-1"}]'
    else
      echo '[]'
    fi
    exit 0
    ;;
  *)
    exit 0
    ;;
esac
`
	writeScript(t, binDir, "bd", bdScript)

	tmuxScript := `#!/bin/sh
if [ "$1" = "has-session" ]; then
  echo "tmux error" 1>&2
  exit 1
fi
exit 0
`
	writeScript(t, binDir, "tmux", tmuxScript)

	t.Setenv("PATH", fmt.Sprintf("%s:%s", binDir, os.Getenv("PATH")))

	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("getwd: %v", err)
	}
	t.Cleanup(func() { _ = os.Chdir(cwd) })
	if err := os.Chdir(townRoot); err != nil {
		t.Fatalf("chdir town root: %v", err)
	}

	started, errs := startPolecatsWithWork(townRoot, rigName)

	if len(started) != 0 {
		t.Fatalf("expected no polecats started, got %v", started)
	}
	if len(errs) != 0 {
		t.Fatalf("expected no errors, got %v", errs)
	}
}

func TestRunSessionCheckSkipsDotDirs(t *testing.T) {
	townRoot := setupTestTownForDotDir(t)
	rigName := "gastown"
	rigPath := filepath.Join(townRoot, rigName)

	addRigEntry(t, townRoot, rigName)

	if err := os.MkdirAll(filepath.Join(rigPath, "polecats", ".claude"), 0755); err != nil {
		t.Fatalf("mkdir .claude polecat: %v", err)
	}

	binDir := t.TempDir()
	tmuxScript := `#!/bin/sh
if [ "$1" = "has-session" ]; then
  echo "can't find session" 1>&2
  exit 1
fi
exit 0
`
	writeScript(t, binDir, "tmux", tmuxScript)
	t.Setenv("PATH", fmt.Sprintf("%s:%s", binDir, os.Getenv("PATH")))

	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("getwd: %v", err)
	}
	t.Cleanup(func() { _ = os.Chdir(cwd) })
	if err := os.Chdir(townRoot); err != nil {
		t.Fatalf("chdir town root: %v", err)
	}

	output := captureStdout(t, func() {
		if err := runSessionCheck(&cobra.Command{}, []string{rigName}); err != nil {
			t.Fatalf("runSessionCheck: %v", err)
		}
	})

	if strings.Contains(output, ".claude") {
		t.Fatalf("expected .claude to be ignored, output:\n%s", output)
	}
}

func addRigEntry(t *testing.T, townRoot, rigName string) {
	t.Helper()

	rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
	rigsConfig, err := config.LoadRigsConfig(rigsPath)
	if err != nil {
		t.Fatalf("load rigs.json: %v", err)
	}
	if rigsConfig.Rigs == nil {
		rigsConfig.Rigs = make(map[string]config.RigEntry)
	}
	rigsConfig.Rigs[rigName] = config.RigEntry{
		GitURL:  "file:///dev/null",
		AddedAt: time.Now(),
	}
	if err := config.SaveRigsConfig(rigsPath, rigsConfig); err != nil {
		t.Fatalf("save rigs.json: %v", err)
	}
}

func setupTestTownForDotDir(t *testing.T) string {
	t.Helper()

	townRoot := t.TempDir()

	mayorDir := filepath.Join(townRoot, "mayor")
	if err := os.MkdirAll(mayorDir, 0755); err != nil {
		t.Fatalf("mkdir mayor: %v", err)
	}

	rigsPath := filepath.Join(mayorDir, "rigs.json")
	rigsConfig := &config.RigsConfig{
		Version: 1,
		Rigs:    make(map[string]config.RigEntry),
	}
	if err := config.SaveRigsConfig(rigsPath, rigsConfig); err != nil {
		t.Fatalf("save rigs.json: %v", err)
	}

	beadsDir := filepath.Join(townRoot, ".beads")
	if err := os.MkdirAll(beadsDir, 0755); err != nil {
		t.Fatalf("mkdir .beads: %v", err)
	}

	return townRoot
}

func writeScript(t *testing.T, dir, name, content string) {
	t.Helper()

	path := filepath.Join(dir, name)
	if err := os.WriteFile(path, []byte(content), 0755); err != nil {
		t.Fatalf("write %s: %v", name, err)
	}
}
