// internal/models/match_result.go package models import ( "time" "gorm.io/gorm" ) // MatchResult represents auto-matching result between lost item and found item type MatchResult struct { ID uint `gorm:"primaryKey" json:"id"` LostItemID uint `gorm:"not null" json:"lost_item_id"` LostItem LostItem `gorm:"foreignKey:LostItemID" json:"lost_item,omitempty"` ItemID uint `gorm:"not null" json:"item_id"` Item Item `gorm:"foreignKey:ItemID" json:"item,omitempty"` SimilarityScore float64 `gorm:"type:decimal(5,2)" json:"similarity_score"` // Percentage match (0-100) MatchedFields string `gorm:"type:text" json:"matched_fields"` // JSON of matched fields MatchedAt time.Time `gorm:"not null" json:"matched_at"` IsNotified bool `gorm:"default:false" json:"is_notified"` // Was user notified? CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` } // TableName specifies the table name for MatchResult model func (MatchResult) TableName() string { return "match_results" } // BeforeCreate hook func (mr *MatchResult) BeforeCreate(tx *gorm.DB) error { if mr.MatchedAt.IsZero() { mr.MatchedAt = time.Now() } return nil } // IsHighMatch checks if similarity score is high (>= 70%) func (mr *MatchResult) IsHighMatch() bool { return mr.SimilarityScore >= 70.0 } // IsMediumMatch checks if similarity score is medium (50-69%) func (mr *MatchResult) IsMediumMatch() bool { return mr.SimilarityScore >= 50.0 && mr.SimilarityScore < 70.0 } // IsLowMatch checks if similarity score is low (< 50%) func (mr *MatchResult) IsLowMatch() bool { return mr.SimilarityScore < 50.0 } // GetMatchLevel returns the match level as string func (mr *MatchResult) GetMatchLevel() string { if mr.IsHighMatch() { return "high" } else if mr.IsMediumMatch() { return "medium" } return "low" } // MatchResultResponse represents match result data for API responses type MatchResultResponse struct { ID uint `json:"id"` LostItemID uint `json:"lost_item_id"` LostItemName string `json:"lost_item_name"` ItemID uint `json:"item_id"` ItemName string `json:"item_name"` ItemPhotoURL string `json:"item_photo_url"` ItemLocation string `json:"item_location"` ItemDateFound time.Time `json:"item_date_found"` ItemStatus string `json:"item_status"` SimilarityScore float64 `json:"similarity_score"` MatchLevel string `json:"match_level"` MatchedFields string `json:"matched_fields"` MatchedAt time.Time `json:"matched_at"` IsNotified bool `json:"is_notified"` } // ToResponse converts MatchResult to MatchResultResponse func (mr *MatchResult) ToResponse() MatchResultResponse { lostItemName := "" if mr.LostItem.ID != 0 { lostItemName = mr.LostItem.Name } itemName := "" itemPhotoURL := "" itemLocation := "" itemDateFound := time.Time{} itemStatus := "" if mr.Item.ID != 0 { itemName = mr.Item.Name itemPhotoURL = mr.Item.PhotoURL itemLocation = mr.Item.Location itemDateFound = mr.Item.DateFound itemStatus = mr.Item.Status } return MatchResultResponse{ ID: mr.ID, LostItemID: mr.LostItemID, LostItemName: lostItemName, ItemID: mr.ItemID, ItemName: itemName, ItemPhotoURL: itemPhotoURL, ItemLocation: itemLocation, ItemDateFound: itemDateFound, ItemStatus: itemStatus, SimilarityScore: mr.SimilarityScore, MatchLevel: mr.GetMatchLevel(), MatchedFields: mr.MatchedFields, MatchedAt: mr.MatchedAt, IsNotified: mr.IsNotified, } } // ItemMatchResponse represents simplified item data for matching display type ItemMatchResponse struct { ID uint `json:"id"` Name string `json:"name"` PhotoURL string `json:"photo_url"` Location string `json:"location"` DateFound time.Time `json:"date_found"` Status string `json:"status"` Similarity float64 `json:"similarity"` }