package domain import ( "context" "time" "gorm.io/datatypes" "gorm.io/gorm" ) type MatchStatus string const ( MatchStatusSuggested MatchStatus = "suggested" MatchStatusNegotiating MatchStatus = "negotiating" MatchStatusReserved MatchStatus = "reserved" MatchStatusContracted MatchStatus = "contracted" MatchStatusLive MatchStatus = "live" MatchStatusFailed MatchStatus = "failed" MatchStatusCancelled MatchStatus = "cancelled" ) // TransportationEstimate represents transportation cost and feasibility type TransportationEstimate struct { CostPerYear float64 `json:"cost_per_year"` Method string `json:"method"` // piping, truck, tanker FeasibilityScore float64 `json:"feasibility_score"` // 0-1 } // RiskAssessment represents different risk factors type RiskAssessment struct { TechnicalRisk float64 `json:"technical_risk"` // 0-1 RegulatoryRisk float64 `json:"regulatory_risk"` // 0-1 MarketRisk float64 `json:"market_risk"` // 0-1 CounterpartyRisk float64 `json:"counterparty_risk,omitempty"` // 0-1 } // EconomicImpact represents economic and environmental impact type EconomicImpact struct { AnnualSavings float64 `json:"annual_savings"` // €/year NPV float64 `json:"npv"` // Net Present Value IRR float64 `json:"irr"` // Internal Rate of Return (%) PaybackYears float64 `json:"payback_years"` // years CO2AvoidedTonnes float64 `json:"co2_avoided_tonnes"` // tonnes/year CapexRequired float64 `json:"capex_required"` // initial investment OpexPerYear float64 `json:"opex_per_year"` // annual operational cost } // NegotiationHistoryEntry represents a single entry in match negotiation history type NegotiationHistoryEntry struct { ID string `gorm:"primaryKey;type:text"` MatchID string `gorm:"not null;type:text;index"` Timestamp time.Time `gorm:"not null;index"` ActorID string `gorm:"type:text;index"` // User who made the change Action string `gorm:"not null;type:varchar(50)"` // proposed, accepted, rejected, counter_offered, etc. Notes string `gorm:"type:text"` OldValue datatypes.JSON `gorm:"type:jsonb"` // Previous value (for status changes, etc.) NewValue datatypes.JSON `gorm:"type:jsonb"` // New value Attachments datatypes.JSON `gorm:"type:jsonb;default:'[]'"` // File URLs, documents Metadata datatypes.JSON `gorm:"type:jsonb;default:'{}'"` // Additional context // Relationships Match *Match `gorm:"foreignKey:MatchID"` } // TableName specifies the table name for GORM func (NegotiationHistoryEntry) TableName() string { return "negotiation_history" } // Enhanced ContractDetails represents contract information when match is formalized type ContractDetails struct { ContractID string `json:"contract_id,omitempty"` SignedAt *time.Time `json:"signed_at,omitempty"` EffectiveFrom *time.Time `json:"effective_from,omitempty"` TerminationDate *time.Time `json:"termination_date,omitempty"` ValuePerYear float64 `json:"value_per_year,omitempty"` TermsURL string `json:"terms_url,omitempty"` PaymentTerms string `json:"payment_terms,omitempty"` TerminationTerms string `json:"termination_terms,omitempty"` Signatures datatypes.JSON `gorm:"type:jsonb;default:'[]'"` // Signer information } // Match represents a potential or actual resource exchange between two organizations type Match struct { ID string `gorm:"primaryKey;type:text"` SourceResourceID string `gorm:"type:text;not null;index:idx_match_resources"` TargetResourceID string `gorm:"type:text;not null;index:idx_match_resources"` Status MatchStatus `gorm:"type:varchar(50);not null;default:'suggested';index"` // Scoring CompatibilityScore float64 `gorm:"type:double precision;not null;index"` // Overall score 0-1 TemporalOverlapScore float64 `gorm:"type:double precision"` // Availability overlap 0-1 QualityScore float64 `gorm:"type:double precision"` // Quality compatibility 0-1 EconomicValue float64 `gorm:"type:double precision;index"` // Estimated annual value € DistanceKm float64 `gorm:"type:double precision;index"` // Priority and reservation Priority int `gorm:"type:integer;default:5;check:priority BETWEEN 1 AND 10"` ReservedUntil *time.Time `gorm:"type:timestamp with time zone"` // Enhanced contract details (replacing JSONB) ContractDetails *ContractDetails `gorm:"embedded;embeddedPrefix:contract_"` // Failure and cancellation tracking FailureReason string `gorm:"type:text"` CancelledBy string `gorm:"type:text;index"` // User ID who cancelled CancelledAt *time.Time `gorm:"type:timestamp with time zone"` // Negotiation history (replacing JSONB with proper relationship) NegotiationHistory []NegotiationHistoryEntry `gorm:"foreignKey:MatchID"` // Legacy JSONB fields (keeping for backward compatibility during migration) TransportationEstimate datatypes.JSON `gorm:"type:jsonb"` // TransportationEstimate RiskAssessment datatypes.JSON `gorm:"type:jsonb"` // RiskAssessment EconomicImpact datatypes.JSON `gorm:"type:jsonb"` // EconomicImpact History datatypes.JSON `gorm:"default:'[]';type:jsonb"` // []MatchHistoryEntry (deprecated) // Optimistic locking Version int `gorm:"type:integer;default:1"` // Timestamps CreatedAt time.Time `gorm:"autoCreateTime;index"` UpdatedAt time.Time `gorm:"autoUpdateTime"` // Associations SourceResource *ResourceFlow `gorm:"foreignKey:SourceResourceID"` TargetResource *ResourceFlow `gorm:"foreignKey:TargetResourceID"` } // TableName specifies the table name for GORM func (Match) TableName() string { return "matches" } // BeforeUpdate increments version for optimistic locking func (m *Match) BeforeUpdate(db *gorm.DB) error { m.Version++ return nil } type MatchRepository interface { Create(ctx context.Context, match *Match) error GetByID(ctx context.Context, id string) (*Match, error) GetByResourceID(ctx context.Context, resourceID string) ([]*Match, error) GetByOrganizationID(ctx context.Context, organizationID string) ([]*Match, error) GetByStatus(ctx context.Context, status MatchStatus) ([]*Match, error) GetTopMatches(ctx context.Context, limit int) ([]*Match, error) // Order by compatibility score Update(ctx context.Context, match *Match) error Delete(ctx context.Context, id string) error // Conflict resolution CheckReservationConflicts(ctx context.Context, resourceID string) ([]*Match, error) UpdateStatus(ctx context.Context, matchID string, newStatus MatchStatus, actor string, notes string) error // Advanced queries for event-driven matching GetByOrganizationIDAndStatus(ctx context.Context, orgID string, status MatchStatus) ([]*Match, error) GetExpiredReservations() ([]*Match, error) GetPendingNegotiations() ([]*Match, error) } // NegotiationHistoryRepository defines the interface for negotiation history data access type NegotiationHistoryRepository interface { Create(ctx context.Context, entry *NegotiationHistoryEntry) error GetByMatchID(ctx context.Context, matchID string) ([]*NegotiationHistoryEntry, error) GetByActorID(ctx context.Context, actorID string) ([]*NegotiationHistoryEntry, error) GetRecentActivity(ctx context.Context, limit int) ([]*NegotiationHistoryEntry, error) }