package services import ( "database/sql" "github.com/rede5/gohorsejobs/backend/internal/models" ) // MetricsService handles job analytics type MetricsService struct { DB *sql.DB } // NewMetricsService creates a new metrics service func NewMetricsService(db *sql.DB) *MetricsService { return &MetricsService{DB: db} } // RecordView records a job view and increments the counter func (s *MetricsService) RecordView(jobID int, userID *int, ip *string, userAgent *string) error { tx, err := s.DB.Begin() if err != nil { return err } defer tx.Rollback() // Insert view record _, err = tx.Exec(` INSERT INTO job_views (job_id, user_id, ip_address, user_agent) VALUES ($1, $2, $3, $4) `, jobID, userID, ip, userAgent) if err != nil { return err } // Increment cached view count _, err = tx.Exec(` UPDATE jobs SET view_count = view_count + 1 WHERE id = $1 `, jobID) if err != nil { return err } return tx.Commit() } // GetJobMetrics returns analytics data for a job func (s *MetricsService) GetJobMetrics(jobID int) (*models.JobMetrics, error) { metrics := &models.JobMetrics{JobID: jobID} // Get view count from jobs table err := s.DB.QueryRow(` SELECT COALESCE(view_count, 0) FROM jobs WHERE id = $1 `, jobID).Scan(&metrics.ViewCount) if err != nil { return nil, err } // Get unique viewers err = s.DB.QueryRow(` SELECT COUNT(DISTINCT COALESCE(user_id::text, ip_address)) FROM job_views WHERE job_id = $1 `, jobID).Scan(&metrics.UniqueViewers) if err != nil { metrics.UniqueViewers = 0 // Don't fail if table doesn't exist yet } // Get application count err = s.DB.QueryRow(` SELECT COUNT(*) FROM applications WHERE job_id = $1 `, jobID).Scan(&metrics.ApplicationCount) if err != nil { metrics.ApplicationCount = 0 } // Calculate conversion rate if metrics.ViewCount > 0 { metrics.ConversionRate = float64(metrics.ApplicationCount) / float64(metrics.ViewCount) * 100 } // Get views last 7 days err = s.DB.QueryRow(` SELECT COUNT(*) FROM job_views WHERE job_id = $1 AND viewed_at > NOW() - INTERVAL '7 days' `, jobID).Scan(&metrics.ViewsLast7Days) if err != nil { metrics.ViewsLast7Days = 0 } // Get views last 30 days err = s.DB.QueryRow(` SELECT COUNT(*) FROM job_views WHERE job_id = $1 AND viewed_at > NOW() - INTERVAL '30 days' `, jobID).Scan(&metrics.ViewsLast30Days) if err != nil { metrics.ViewsLast30Days = 0 } return metrics, nil }