package customer import ( "github.com/damirmukimov/city_resource_graph/models/params" ) // CustomerMetrics represents customer adoption metrics for a given year. type CustomerMetrics struct { TotalOrgs int `json:"total_orgs"` // Total active organizations (after churn) PayingOrgs int `json:"paying_orgs"` // Active paying organizations FreeOrgs int `json:"free_orgs"` // Active free tier organizations PayingShare float64 `json:"paying_share"` // Percentage paying (0.0-1.0) NewAcquisitions int `json:"new_acquisitions"` // New organizations acquired this year ChurnedOrgs int `json:"churned_orgs"` // Organizations that churned this year CumulativeOrgs int `json:"cumulative_orgs"` // Cumulative organizations ever acquired } // TierDistribution represents the distribution of paying customers across tiers. type TierDistribution struct { Basic int `json:"basic"` // Number of Basic tier customers Business int `json:"business"` // Number of Business tier customers Enterprise int `json:"enterprise"` // Number of Enterprise tier customers Total int `json:"total"` // Total paying customers } // ChurnMetrics represents churn and retention metrics per tier. type ChurnMetrics struct { Basic TierChurn `json:"basic"` Business TierChurn `json:"business"` Enterprise TierChurn `json:"enterprise"` } // TierChurn represents churn metrics for a single tier. type TierChurn struct { AnnualChurn float64 `json:"annual_churn"` // Annual churn rate (0.0-1.0) Retention float64 `json:"retention"` // Retention rate (1.0 - churn) AvgLifetimeMonths int `json:"avg_lifetime_months"` // Average customer lifetime in months } // DefaultChurnMetrics returns default churn metrics per tier. func DefaultChurnMetrics() ChurnMetrics { return ChurnMetrics{ Basic: TierChurn{ AnnualChurn: 0.15, // 15% Retention: 0.85, // 85% AvgLifetimeMonths: 48, // 4 years (conservative) }, Business: TierChurn{ AnnualChurn: 0.10, // 10% Retention: 0.90, // 90% AvgLifetimeMonths: 64, // 5.3 years (conservative) }, Enterprise: TierChurn{ AnnualChurn: 0.05, // 5% Retention: 0.95, // 95% AvgLifetimeMonths: 80, // 6.7 years (conservative) }, } } // CalculateCustomerMetrics computes customer adoption metrics for a given year. func CalculateCustomerMetrics(year int, p *params.Params) CustomerMetrics { totalOrgs := p.Adoption.TotalOrgs.GetYear(year) payingShare := p.Adoption.PayingShare.GetYear(year) payingOrgs := int(float64(totalOrgs) * payingShare) freeOrgs := totalOrgs - payingOrgs // For churn modeling, estimate new acquisitions vs cumulative // In a simplified model, assume all customers are "new" for the target year // Churn rates are used in LTV calculations rather than reducing active customers newAcquisitions := totalOrgs churnedOrgs := 0 // Not modeled as reducing active base in this simplified approach cumulativeOrgs := totalOrgs // Simplified - doesn't track across years return CustomerMetrics{ TotalOrgs: totalOrgs, PayingOrgs: payingOrgs, FreeOrgs: freeOrgs, PayingShare: payingShare, NewAcquisitions: newAcquisitions, ChurnedOrgs: churnedOrgs, CumulativeOrgs: cumulativeOrgs, } } // CalculateTierDistribution computes the distribution of paying customers across tiers. func CalculateTierDistribution(year int, payingOrgs int, p *params.Params) TierDistribution { tierMix := p.Pricing.TierMix.GetYear(year) basic := int(float64(payingOrgs) * tierMix.Basic) business := int(float64(payingOrgs) * tierMix.Business) enterprise := int(float64(payingOrgs) * tierMix.Enterprise) // Handle rounding - ensure total matches total := basic + business + enterprise if total != payingOrgs { // Adjust basic tier to account for rounding differences basic += payingOrgs - total } return TierDistribution{ Basic: basic, Business: business, Enterprise: enterprise, Total: payingOrgs, } }