package loop

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"sort"
	"strings"
	"sync"
	"time"

	"tailscale.com/portlist"
)

// PortMonitor monitors open/listening TCP ports and sends notifications
// to an Agent when ports are detected or removed.
type PortMonitor struct {
	mu       sync.RWMutex
	ports    []portlist.Port // cached list of current ports
	poller   *portlist.Poller
	agent    *Agent
	ctx      context.Context
	cancel   context.CancelFunc
	interval time.Duration
	running  bool
	wg       sync.WaitGroup
}

// NewPortMonitor creates a new PortMonitor instance.
func NewPortMonitor(agent *Agent, interval time.Duration) *PortMonitor {
	if interval <= 0 {
		interval = 5 * time.Second // default polling interval
	}

	ctx, cancel := context.WithCancel(context.Background())
	poller := &portlist.Poller{
		IncludeLocalhost: true, // include localhost-bound services
	}

	return &PortMonitor{
		poller:   poller,
		agent:    agent,
		ctx:      ctx,
		cancel:   cancel,
		interval: interval,
	}
}

// Start begins monitoring ports in a background goroutine.
func (pm *PortMonitor) Start(ctx context.Context) error {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.running {
		return fmt.Errorf("port monitor is already running")
	}

	// Update the internal context to use the provided context
	pm.cancel() // Cancel the old context
	pm.ctx, pm.cancel = context.WithCancel(ctx)

	pm.running = true
	pm.wg.Add(1)

	// Do initial port scan
	if err := pm.initialScan(); err != nil {
		pm.running = false
		pm.wg.Done()
		return fmt.Errorf("initial port scan failed: %w", err)
	}

	go pm.monitor()
	return nil
}

// Stop stops the port monitor.
func (pm *PortMonitor) Stop() {
	pm.mu.Lock()
	if !pm.running {
		pm.mu.Unlock()
		return
	}

	pm.running = false
	pm.cancel()
	pm.mu.Unlock()
	pm.wg.Wait()
	pm.poller.Close()
}

// GetPorts returns the cached list of open ports.
func (pm *PortMonitor) GetPorts() []portlist.Port {
	pm.mu.RLock()
	defer pm.mu.RUnlock()

	// Return a copy to prevent data races
	ports := make([]portlist.Port, len(pm.ports))
	copy(ports, pm.ports)
	return ports
}

// initialScan performs the initial port scan without sending notifications.
func (pm *PortMonitor) initialScan() error {
	ports, _, err := pm.poller.Poll()
	if err != nil {
		return err
	}

	// Filter for TCP ports only
	pm.ports = filterTCPPorts(ports)
	sortPorts(pm.ports)

	return nil
}

// monitor runs the port monitoring loop.
func (pm *PortMonitor) monitor() {
	defer pm.wg.Done()

	ticker := time.NewTicker(pm.interval)
	defer ticker.Stop()

	for {
		select {
		case <-pm.ctx.Done():
			return
		case <-ticker.C:
			if err := pm.checkPorts(); err != nil {
				slog.WarnContext(pm.ctx, "port monitoring error", "error", err)
			}
		}
	}
}

// checkPorts polls for current ports and sends notifications for changes.
func (pm *PortMonitor) checkPorts() error {
	ports, changed, err := pm.poller.Poll()
	if err != nil {
		return err
	}

	if !changed {
		return nil
	}

	// Filter for TCP ports only
	currentTCPPorts := filterTCPPorts(ports)
	sortPorts(currentTCPPorts)

	pm.mu.Lock()
	previousPorts := pm.ports
	pm.ports = currentTCPPorts
	pm.mu.Unlock()

	// Find added and removed ports
	addedPorts := findAddedPorts(previousPorts, currentTCPPorts)
	removedPorts := findRemovedPorts(previousPorts, currentTCPPorts)

	// Send notifications for changes
	for _, port := range addedPorts {
		pm.sendPortNotification("opened", port)
	}

	for _, port := range removedPorts {
		pm.sendPortNotification("closed", port)
	}

	return nil
}

// sendPortNotification sends a port event notification to the agent.
func (pm *PortMonitor) sendPortNotification(event string, port portlist.Port) {
	if pm.agent == nil {
		return
	}

	// Skip low ports and sketch's ports
	if port.Port < 1024 || port.Pid == 1 {
		return
	}

	// Skip processes with SKETCH_IGNORE_PORTS environment variable
	if pm.shouldIgnoreProcess(port.Pid) {
		return
	}

	// TODO: Structure this so that UI can display it more nicely.
	content := fmt.Sprintf("Port %s: %s:%d", event, port.Proto, port.Port)
	if port.Process != "" {
		content += fmt.Sprintf(" (process: %s)", port.Process)
	}
	if port.Pid != 0 {
		content += fmt.Sprintf(" (pid: %d)", port.Pid)
	}

	msg := AgentMessage{
		Type:    PortMessageType,
		Content: content,
	}

	pm.agent.pushToOutbox(pm.ctx, msg)
}

// filterTCPPorts filters the port list to include only TCP ports.
func filterTCPPorts(ports []portlist.Port) []portlist.Port {
	var tcpPorts []portlist.Port
	for _, port := range ports {
		if port.Proto == "tcp" {
			tcpPorts = append(tcpPorts, port)
		}
	}
	return tcpPorts
}

// sortPorts sorts ports by port number for consistent comparisons.
func sortPorts(ports []portlist.Port) {
	sort.Slice(ports, func(i, j int) bool {
		return ports[i].Port < ports[j].Port
	})
}

// findAddedPorts finds ports that are in current but not in previous.
func findAddedPorts(previous, current []portlist.Port) []portlist.Port {
	prevSet := make(map[uint16]bool)
	for _, port := range previous {
		prevSet[port.Port] = true
	}

	var added []portlist.Port
	for _, port := range current {
		if !prevSet[port.Port] {
			added = append(added, port)
		}
	}
	return added
}

// findRemovedPorts finds ports that are in previous but not in current.
func findRemovedPorts(previous, current []portlist.Port) []portlist.Port {
	currentSet := make(map[uint16]bool)
	for _, port := range current {
		currentSet[port.Port] = true
	}

	var removed []portlist.Port
	for _, port := range previous {
		if !currentSet[port.Port] {
			removed = append(removed, port)
		}
	}
	return removed
}

// shouldIgnoreProcess checks if a process should be ignored based on its environment variables.
func (pm *PortMonitor) shouldIgnoreProcess(pid int) bool {
	if pid <= 0 {
		return false
	}

	// Read the process environment from /proc/[pid]/environ
	envFile := fmt.Sprintf("/proc/%d/environ", pid)
	envData, err := os.ReadFile(envFile)
	if err != nil {
		// If we can't read the environment, don't ignore the process
		return false
	}

	// Parse the environment variables (null-separated)
	envVars := strings.Split(string(envData), "\x00")
	for _, envVar := range envVars {
		if envVar == "SKETCH_IGNORE_PORTS=1" {
			return true
		}
	}

	return false
}
