package services import ( "errors" "fmt" "regexp" "strings" "gauth-central/internal/database" "gauth-central/internal/models" "gorm.io/gorm" ) const defaultHomeVideoURL = "https://www.youtube.com/watch?v=6zM4p_A0ISk" type HomeService struct{} func NewHomeService() *HomeService { return &HomeService{} } // CreateHome creates a new home entry with optional tag relations. func (s *HomeService) CreateHome( name string, title string, button1 string, button2 string, video string, keywords string, image string, tagIDs []string, isActive bool, ) (*models.Home, error) { if strings.TrimSpace(video) == "" { video = defaultHomeVideoURL } slug := s.generateUniqueSlug(slugify(name), "") home := models.Home{ Name: name, Title: title, Button1: button1, Button2: button2, Video: video, Keywords: keywords, Image: image, Slug: slug, IsActive: isActive, } if len(tagIDs) > 0 { tags, err := s.fetchTagsByIDs(tagIDs) if err != nil { return nil, err } home.Tags = tags } if err := database.DB.Create(&home).Error; err != nil { return nil, err } return s.GetHomeByID(home.ID.String()) } // GetAllHomes retrieves all homes. Use onlyActive to filter public data. func (s *HomeService) GetAllHomes(onlyActive bool) ([]models.Home, error) { var homes []models.Home query := database.DB.Preload("Tags").Order("created_at desc") if onlyActive { query = query.Where("is_active = ?", true) } if err := query.Find(&homes).Error; err != nil { return nil, err } return homes, nil } // GetHomeByID retrieves a home by ID. func (s *HomeService) GetHomeByID(id string) (*models.Home, error) { var home models.Home if err := database.DB.Preload("Tags").Where("id = ?", id).First(&home).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("home not found") } return nil, err } return &home, nil } // GetHomeBySlug retrieves a home by slug. Use onlyActive to limit public access. func (s *HomeService) GetHomeBySlug(slug string, onlyActive bool) (*models.Home, error) { var home models.Home query := database.DB.Preload("Tags").Where("slug = ?", slug) if onlyActive { query = query.Where("is_active = ?", true) } if err := query.First(&home).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("home not found") } return nil, err } return &home, nil } // UpdateHome updates an existing home entry and its tag relations. func (s *HomeService) UpdateHome( id string, name *string, title *string, button1 *string, button2 *string, video *string, keywords *string, image *string, slug *string, tagIDs *[]string, isActive *bool, ) (*models.Home, error) { home, err := s.GetHomeByID(id) if err != nil { return nil, err } updates := map[string]interface{}{} if name != nil { updates["name"] = *name } if title != nil { updates["title"] = *title } if button1 != nil { updates["button1"] = *button1 } if button2 != nil { updates["button2"] = *button2 } if video != nil { updates["video"] = *video } if keywords != nil { updates["keywords"] = *keywords } if image != nil { updates["image"] = *image } if slug != nil { clean := slugify(*slug) if clean == "" { return nil, errors.New("slug cannot be empty") } if s.slugExists(clean, id) { return nil, errors.New("slug already exists") } updates["slug"] = clean } if isActive != nil { updates["is_active"] = *isActive } if len(updates) > 0 { if err := database.DB.Model(home).Updates(updates).Error; err != nil { return nil, err } } if tagIDs != nil { tags, err := s.fetchTagsByIDs(*tagIDs) if err != nil { return nil, err } if err := database.DB.Model(home).Association("Tags").Replace(tags); err != nil { return nil, err } } return s.GetHomeByID(id) } // DeleteHome deletes a home by ID. func (s *HomeService) DeleteHome(id string) error { result := database.DB.Delete(&models.Home{}, "id = ?", id) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return errors.New("home not found") } return nil } func (s *HomeService) fetchTagsByIDs(tagIDs []string) ([]models.Tag, error) { var tags []models.Tag if len(tagIDs) == 0 { return tags, nil } if err := database.DB.Where("id IN ?", tagIDs).Find(&tags).Error; err != nil { return nil, err } if len(tags) != len(tagIDs) { return nil, errors.New("one or more tags not found") } return tags, nil } func (s *HomeService) generateUniqueSlug(baseSlug string, excludeID string) string { slug := baseSlug counter := 1 for s.slugExists(slug, excludeID) { slug = fmt.Sprintf("%s-%d", baseSlug, counter) counter++ } return slug } func (s *HomeService) slugExists(slug string, excludeID string) bool { var count int64 query := database.DB.Model(&models.Home{}).Where("slug = ?", slug) if excludeID != "" { query = query.Where("id <> ?", excludeID) } query.Count(&count) return count > 0 } func slugify(input string) string { clean := strings.TrimSpace(input) if clean == "" { return "" } replacer := strings.NewReplacer( "ı", "i", "İ", "i", "ş", "s", "Ş", "s", "ğ", "g", "Ğ", "g", "ç", "c", "Ç", "c", "ö", "o", "Ö", "o", "ü", "u", "Ü", "u", ) clean = strings.ToLower(replacer.Replace(clean)) re := regexp.MustCompile(`[^a-z0-9]+`) clean = re.ReplaceAllString(clean, "-") clean = strings.Trim(clean, "-") if clean == "" { return "home" } return clean }