package doctor

import (
	"fmt"
	"path/filepath"
	"strings"

	"github.com/steveyegge/gastown/internal/beads"
	"github.com/steveyegge/gastown/internal/config"
	"github.com/steveyegge/gastown/internal/session"
	"github.com/steveyegge/gastown/internal/tmux"
)

// SessionEnvReader abstracts tmux session environment access for testing.
type SessionEnvReader interface {
	ListSessions() ([]string, error)
	GetAllEnvironment(session string) (map[string]string, error)
}

// tmuxEnvReader wraps real tmux operations.
type tmuxEnvReader struct {
	t *tmux.Tmux
}

func (r *tmuxEnvReader) ListSessions() ([]string, error) {
	return r.t.ListSessions()
}

func (r *tmuxEnvReader) GetAllEnvironment(session string) (map[string]string, error) {
	return r.t.GetAllEnvironment(session)
}

// EnvVarsCheck verifies that tmux session environment variables match expected values.
type EnvVarsCheck struct {
	BaseCheck
	reader SessionEnvReader // nil means use real tmux
}

// NewEnvVarsCheck creates a new env vars check.
func NewEnvVarsCheck() *EnvVarsCheck {
	return &EnvVarsCheck{
		BaseCheck: BaseCheck{
			CheckName:        "env-vars",
			CheckDescription: "Verify tmux session environment variables match expected values",
		},
	}
}

// NewEnvVarsCheckWithReader creates a check with a custom reader (for testing).
func NewEnvVarsCheckWithReader(reader SessionEnvReader) *EnvVarsCheck {
	c := NewEnvVarsCheck()
	c.reader = reader
	return c
}

// Run checks environment variables for all Gas Town sessions.
func (c *EnvVarsCheck) Run(ctx *CheckContext) *CheckResult {
	reader := c.reader
	if reader == nil {
		reader = &tmuxEnvReader{t: tmux.NewTmux()}
	}

	sessions, err := reader.ListSessions()
	if err != nil {
		// No tmux server - treat as success (valid when Gas Town is down)
		return &CheckResult{
			Name:    c.Name(),
			Status:  StatusOK,
			Message: "No tmux sessions running",
		}
	}

	// Filter to Gas Town sessions only (gt-* and hq-*)
	var gtSessions []string
	for _, sess := range sessions {
		if strings.HasPrefix(sess, "gt-") || strings.HasPrefix(sess, "hq-") {
			gtSessions = append(gtSessions, sess)
		}
	}

	if len(gtSessions) == 0 {
		// No Gas Town sessions - treat as success (valid when Gas Town is down)
		return &CheckResult{
			Name:    c.Name(),
			Status:  StatusOK,
			Message: "No Gas Town sessions running",
		}
	}

	var mismatches []string
	checkedCount := 0

	for _, sess := range gtSessions {
		identity, err := session.ParseSessionName(sess)
		if err != nil {
			// Skip unparseable sessions
			continue
		}

		// Get expected env vars based on role, emulating real call sites
		// Town-level roles use TownRoot for beads, rig-level roles use rig path
		var beadsDir string
		if identity.Rig != "" {
			rigPath := filepath.Join(ctx.TownRoot, identity.Rig)
			beadsDir = beads.ResolveBeadsDir(rigPath)
		} else {
			beadsDir = beads.ResolveBeadsDir(ctx.TownRoot)
		}
		expected := config.AgentEnv(config.AgentEnvConfig{
			Role:      string(identity.Role),
			Rig:       identity.Rig,
			AgentName: identity.Name,
			TownRoot:  ctx.TownRoot,
			BeadsDir:  beadsDir,
		})

		// Get actual tmux env vars
		actual, err := reader.GetAllEnvironment(sess)
		if err != nil {
			mismatches = append(mismatches, fmt.Sprintf("%s: could not read env vars: %v", sess, err))
			continue
		}

		checkedCount++

		// Compare each expected var
		for key, expectedVal := range expected {
			actualVal, exists := actual[key]
			if !exists {
				mismatches = append(mismatches, fmt.Sprintf("%s: missing %s (expected %q)", sess, key, expectedVal))
			} else if actualVal != expectedVal {
				mismatches = append(mismatches, fmt.Sprintf("%s: %s=%q (expected %q)", sess, key, actualVal, expectedVal))
			}
		}
	}

	if len(mismatches) == 0 {
		return &CheckResult{
			Name:    c.Name(),
			Status:  StatusOK,
			Message: fmt.Sprintf("All %d session(s) have correct environment variables", checkedCount),
		}
	}

	// Add explanation about needing restart
	details := append(mismatches,
		"",
		"Note: Mismatched session env vars won't affect running Claude until sessions restart.",
	)

	return &CheckResult{
		Name:    c.Name(),
		Status:  StatusWarning,
		Message: fmt.Sprintf("Found %d env var mismatch(es) across %d session(s)", len(mismatches), checkedCount),
		Details: details,
		FixHint: "Run 'gt shutdown && gt up' to restart sessions with correct env vars",
	}
}
