Files
aicyclingcoach-go/internal/tui/models/activity.go
2025-09-17 17:30:18 -07:00

99 lines
3.3 KiB
Go

package models
import (
"fmt"
"time"
"github.com/sstent/fitness-tui/internal/types"
)
type Activity struct {
ID string
Name string
Description string
Type string // Garmin activity type (e.g., "running", "cycling")
ActivityType string // Activity type for AI analysis prompts (e.g., "running", "cycling", "hiking")
Date time.Time
Duration time.Duration
Distance float64 // meters
Elevation float64
Calories int // in kilocalories
Metrics ActivityMetrics
FilePath string // Path to original activity file (e.g., GPX/FIT)
}
type ActivityMetrics struct {
// Core metrics
AvgHeartRate int
MaxHeartRate int
AvgPace float64 // seconds per km
AvgSpeed float64 // km/h
ElevationGain float64 // meters
ElevationLoss float64 // meters
RecoveryTime int // hours
IntensityFactor float64
// Raw data streams
HeartRateData []float64 `json:"heart_rate_data"`
ElevationData []float64 `json:"elevation_data"`
PowerData []float64 `json:"power_data,omitempty"`
CadenceData []float64 `json:"cadence_data,omitempty"`
SpeedData []float64 `json:"speed_data,omitempty"`
TemperatureData []float64 `json:"temperature_data,omitempty"`
// Downsampled metrics (for AI analysis)
DownsampledHR []types.DownsampledPoint `json:"downsampled_hr,omitempty"`
DownsampledPower []types.DownsampledPoint `json:"downsampled_power,omitempty"`
DownsampledCadence []types.DownsampledPoint `json:"downsampled_cadence,omitempty"`
DownsampledSpeed []types.DownsampledPoint `json:"downsampled_speed,omitempty"`
// Power metrics
AvgPower float64 `json:"avg_power"`
MaxPower float64 `json:"max_power"`
NormalizedPower float64 `json:"normalized_power"`
FTP float64 `json:"ftp"` // Functional Threshold Power
// Cadence metrics
AvgCadence float64 `json:"avg_cadence"`
MaxCadence float64 `json:"max_cadence"`
// Running metrics
GroundContactTime int `json:"ground_contact_time"` // milliseconds
VerticalOscillation int `json:"vertical_oscillation"` // millimeters
// Hiking metrics
AscentRate float64 `json:"ascent_rate"` // meters/hour
DescentRate float64 `json:"descent_rate"` // meters/hour
AvgTemperature float64 `json:"avg_temperature"` // Celsius
// Analysis-specific fields
TargetZones string `json:"target_zones"` // e.g., "Z2: 115-140bpm"
TrainingLoad float64 `json:"training_load"` // Training load score
TrainingStressScore float64 `json:"training_stress_score"` // TSS score
ElevationProfile string `json:"elevation_profile"` // e.g., "Hilly with 3 major climbs"
FatigueLevel string `json:"fatigue_level"` // e.g., "Moderate"
}
func (a *Activity) FormattedDuration() string {
hours := int(a.Duration.Hours())
minutes := int(a.Duration.Minutes()) % 60
seconds := int(a.Duration.Seconds()) % 60
if hours > 0 {
return fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
}
return fmt.Sprintf("%02d:%02d", minutes, seconds)
}
func (a *Activity) FormattedDistance() string {
return fmt.Sprintf("%.2fkm", a.Distance/1000)
}
func (a *Activity) FormattedPace() string {
if a.Metrics.AvgPace <= 0 {
return "--:--"
}
minutes := int(a.Metrics.AvgPace) / 60
seconds := int(a.Metrics.AvgPace) % 60
return fmt.Sprintf("%d:%02d/km", minutes, seconds)
}