// Package telemetry provides application telemetry
package telemetry

import (
	"bufio"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/jfraeys/fetch_ml/internal/logging"
)

// IOStats represents process I/O statistics.
type IOStats struct {
	ReadBytes  uint64
	WriteBytes uint64
}

// ReadProcessIO reads I/O statistics from /proc/self/io.
func ReadProcessIO() (IOStats, error) {
	f, err := os.Open("/proc/self/io")
	if err != nil {
		return IOStats{}, err
	}
	defer func() { _ = f.Close() }()

	var stats IOStats
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "read_bytes:") {
			stats.ReadBytes = parseUintField(line)
		}
		if strings.HasPrefix(line, "write_bytes:") {
			stats.WriteBytes = parseUintField(line)
		}
	}
	if err := scanner.Err(); err != nil {
		return IOStats{}, err
	}
	return stats, nil
}

// DiffIO calculates the difference between two IOStats snapshots.
func DiffIO(before, after IOStats) IOStats {
	var delta IOStats
	if after.ReadBytes >= before.ReadBytes {
		delta.ReadBytes = after.ReadBytes - before.ReadBytes
	}
	if after.WriteBytes >= before.WriteBytes {
		delta.WriteBytes = after.WriteBytes - before.WriteBytes
	}
	return delta
}

func parseUintField(line string) uint64 {
	parts := strings.Split(line, ":")
	if len(parts) != 2 {
		return 0
	}
	value, err := strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 64)
	if err != nil {
		return 0
	}
	return value
}

// ExecWithMetrics executes a function with timing and logging.
func ExecWithMetrics(
	logger *logging.Logger,
	description string,
	threshold time.Duration,
	fn func() (string, error),
) (string, error) {
	start := time.Now()
	out, err := fn()
	duration := time.Since(start)
	if duration > threshold {
		fields := []any{"latency_ms", duration.Milliseconds(), "command", description}
		if err != nil {
			fields = append(fields, "error", err)
		}
		logger.Debug("ssh exec", fields...)
	}
	return out, err
}
