package agentexec

import (
	"regexp"
	"strings"
)

// CommandPolicy defines what commands are allowed, blocked, or require approval
type CommandPolicy struct {
	// AutoApprove patterns - commands matching these are automatically allowed
	AutoApprove []string

	// RequireApproval patterns - commands matching these need user approval
	RequireApproval []string

	// Blocked patterns - commands matching these are never allowed
	Blocked []string

	// compiled regex patterns
	autoApproveRe     []*regexp.Regexp
	requireApprovalRe []*regexp.Regexp
	blockedRe         []*regexp.Regexp
}

// DefaultPolicy returns a sensible default command policy
func DefaultPolicy() *CommandPolicy {
	p := &CommandPolicy{
		AutoApprove: []string{
			// System inspection
			`^ps(\s|$)`,
			`^top\s+-bn`,
			`^df(\s|$)`,
			`^free(\s|$)`,
			`^uptime$`,
			`^hostname$`,
			`^uname(\s|$)`,
			`^cat\s+/proc/`,
			`^cat\s+/etc/os-release`,
			`^lsof(\s|$)`,
			`^netstat(\s|$)`,
			`^ss(\s|$)`,
			`^ip\s+(addr|route|link)`,
			`^ifconfig`,
			`^w$`,
			`^who$`,
			`^last(\s|$)`,

			// Log reading (read-only)
			`^cat\s+/var/log/`,
			`^tail\s+.*(/var/log/|/log/)`,
			`^head\s+.*(/var/log/|/log/)`,
			`^grep\s+.*(/var/log/|/log/)`,
			`^journalctl\s`,

			// Service status (read-only)
			`^systemctl\s+status\s`,
			`^systemctl\s+is-active\s`,
			`^systemctl\s+is-enabled\s`,
			`^systemctl\s+list-units`,
			`^service\s+\S+\s+status`,

			// Docker inspection (read-only)
			`^docker\s+ps`,
			`^docker\s+logs\s`,
			`^docker\s+inspect\s`,
			`^docker\s+stats\s+--no-stream`,
			`^docker\s+top\s`,
			`^docker\s+images`,
			`^docker\s+network\s+ls`,
			`^docker\s+volume\s+ls`,

			// Proxmox inspection (read-only)
			`^pct\s+list`,
			`^pct\s+config\s`,
			`^pct\s+status\s`,
			`^qm\s+list`,
			`^qm\s+config\s`,
			`^qm\s+status\s`,
			`^pvesh\s+get\s`,

			// Disk/storage info
			`^lsblk`,
			`^blkid`,
			`^fdisk\s+-l`,
			`^du(\s|$)`,
			`^ls(\s|$)`,
			`^stat(\s|$)`,
			`^file(\s|$)`,
			`^find\s+/.*-size`,  // Find large files
			`^find\s+/.*-mtime`, // Find by modification time
			`^find\s+/.*-type`,  // Find by type

			// Memory inspection
			`^vmstat`,
			`^sar\s`,
			`^iostat`,
			`^mpstat`,

			// Docker inspection (read-only)
			`^docker\s+system\s+df`,

			// APT inspection (read-only)
			`^apt\s+list`,
			`^apt-cache\s`,
			`^dpkg\s+-l`,
			`^dpkg\s+--list`,
		},

		RequireApproval: []string{
			// Service control
			`^systemctl\s+(restart|stop|start|reload)\s`,
			`^service\s+\S+\s+(restart|stop|start|reload)`,

			// Docker control
			`^docker\s+(restart|stop|start|kill)\s`,
			`^docker\s+exec\s`,
			`^docker\s+rm\s`,

			// Process control
			`^kill\s`,
			`^pkill\s`,
			`^killall\s`,

			// Package management
			`^apt\s`,
			`^apt-get\s`,
			`^yum\s`,
			`^dnf\s`,
			`^pacman\s`,

			// Proxmox control
			`^pct\s+(start|stop|shutdown|reboot|resize|set)\s`,
			`^qm\s+(start|stop|shutdown|reboot|reset|resize|set)\s`,

			// journalctl maintenance (modifies logs / persistent state)
			`^journalctl\s+--vacuum`,
			`^journalctl\s+--rotate`,
		},

		Blocked: []string{
			// Destructive filesystem operations
			`rm\s+-rf\s+/`,
			`rm\s+--no-preserve-root`,
			`mkfs`,
			`dd\s+.*of=/dev/`,
			`>\s*/dev/sd`,
			`>\s*/dev/nvme`,

			// System destruction
			`shutdown`,
			`reboot`,
			`init\s+0`,
			`poweroff`,
			`halt`,

			// Dangerous permissions
			`chmod\s+777`,
			`chmod\s+-R\s+777`,
			`chown\s+-R\s+.*:.*\s+/`,

			// Remote code execution
			`curl.*\|\s*(ba)?sh`,
			`wget.*\|\s*(ba)?sh`,
			`bash\s+-c\s+.*curl`,
			`bash\s+-c\s+.*wget`,

			// Crypto mining indicators
			`xmrig`,
			`minerd`,
			`cpuminer`,

			// Fork bomb patterns
			`:\(\)\s*{\s*:\s*\|\s*:`,

			// Clear system logs
			`>\s*/var/log/`,
			`truncate.*--size.*0.*/var/log/`,
		},
	}

	p.compile()
	return p
}

func (p *CommandPolicy) compile() {
	p.autoApproveRe = compilePatterns(p.AutoApprove)
	p.requireApprovalRe = compilePatterns(p.RequireApproval)
	p.blockedRe = compilePatterns(p.Blocked)
}

func compilePatterns(patterns []string) []*regexp.Regexp {
	result := make([]*regexp.Regexp, 0, len(patterns))
	for _, pattern := range patterns {
		re, err := regexp.Compile(pattern)
		if err == nil {
			result = append(result, re)
		}
	}
	return result
}

// PolicyDecision represents the policy decision for a command
type PolicyDecision string

const (
	PolicyAllow           PolicyDecision = "allow"
	PolicyRequireApproval PolicyDecision = "require_approval"
	PolicyBlock           PolicyDecision = "block"
)

// Evaluate checks a command against the policy
func (p *CommandPolicy) Evaluate(command string) PolicyDecision {
	command = strings.TrimSpace(command)
	// Normalize simple sudo prefix so policy applies consistently.
	// For complex sudo invocations (sudo flags), keep the command as-is (conservative).
	if strings.HasPrefix(command, "sudo ") {
		parts := strings.Fields(command)
		if len(parts) >= 2 && !strings.HasPrefix(parts[1], "-") {
			command = strings.Join(parts[1:], " ")
		}
	}

	// Check blocked first (highest priority)
	for _, re := range p.blockedRe {
		if re.MatchString(command) {
			return PolicyBlock
		}
	}

	// Check require approval
	for _, re := range p.requireApprovalRe {
		if re.MatchString(command) {
			return PolicyRequireApproval
		}
	}

	// Check auto-approve
	for _, re := range p.autoApproveRe {
		if re.MatchString(command) {
			return PolicyAllow
		}
	}

	// Default: require approval for unknown commands
	return PolicyRequireApproval
}

// IsBlocked returns true if a command is blocked
func (p *CommandPolicy) IsBlocked(command string) bool {
	return p.Evaluate(command) == PolicyBlock
}

// NeedsApproval returns true if a command needs user approval
func (p *CommandPolicy) NeedsApproval(command string) bool {
	return p.Evaluate(command) == PolicyRequireApproval
}

// IsAutoApproved returns true if a command can run without approval
func (p *CommandPolicy) IsAutoApproved(command string) bool {
	return p.Evaluate(command) == PolicyAllow
}
