package services

import (
	"errors"
	"fmt"
	"regexp"
	"strings"

	"gauth-central/internal/database"
	"gauth-central/internal/models"

	"gorm.io/gorm"
)

type AboutService struct{}

func NewAboutService() *AboutService {
	return &AboutService{}
}

// CreateAbout creates a new about entry.
func (s *AboutService) CreateAbout(
	title string,
	image string,
	imageSub string,
	cv string,
	birthday string,
	city string,
	study string,
	website string,
	phone string,
	age string,
	interests string,
	degree string,
	x string,
	mail string,
	done *int,
	projectDone string,
	userH *int,
	hapyUser string,
	great *int,
	greatReviews string,
	team *int,
	supportTeam string,
	isActive bool,
	counterActive bool,
) (*models.About, error) {
	slug := s.generateUniqueSlug(slugifyAbout(title), "")

	about := models.About{
		Title:         title,
		Image:         image,
		ImageSub:      imageSub,
		CV:            cv,
		Birthday:      birthday,
		City:          city,
		Study:         study,
		Website:       website,
		Phone:         phone,
		Age:           age,
		Interests:     interests,
		Degree:        degree,
		X:             x,
		Mail:          mail,
		Done:          done,
		ProjectDone:   projectDone,
		UserH:         userH,
		HapyUser:      hapyUser,
		Great:         great,
		GreatReviews:  greatReviews,
		Team:          team,
		SupportTeam:   supportTeam,
		Slug:          slug,
		IsActive:      isActive,
		CounterActive: counterActive,
	}

	if err := database.DB.Create(&about).Error; err != nil {
		return nil, err
	}

	return s.GetAboutByID(about.ID.String())
}

// GetAllAbout retrieves all about entries. Use onlyActive to filter public data.
func (s *AboutService) GetAllAbout(onlyActive bool) ([]models.About, error) {
	var abouts []models.About
	query := database.DB.Order("created_at desc")
	if onlyActive {
		query = query.Where("is_active = ?", true)
	}

	if err := query.Find(&abouts).Error; err != nil {
		return nil, err
	}

	return abouts, nil
}

// GetFirstActiveAbout returns the newest active about entry.
func (s *AboutService) GetFirstActiveAbout() (*models.About, error) {
	var about models.About
	if err := database.DB.Where("is_active = ?", true).Order("created_at desc").First(&about).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("about not found")
		}
		return nil, err
	}
	return &about, nil
}

// GetAboutByID retrieves an about entry by ID.
func (s *AboutService) GetAboutByID(id string) (*models.About, error) {
	var about models.About
	if err := database.DB.Where("id = ?", id).First(&about).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("about not found")
		}
		return nil, err
	}
	return &about, nil
}

// GetAboutBySlug retrieves an about entry by slug. Use onlyActive to limit public access.
func (s *AboutService) GetAboutBySlug(slug string, onlyActive bool) (*models.About, error) {
	var about models.About
	query := database.DB.Where("slug = ?", slug)
	if onlyActive {
		query = query.Where("is_active = ?", true)
	}

	if err := query.First(&about).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("about not found")
		}
		return nil, err
	}

	return &about, nil
}

// UpdateAbout updates an existing about entry.
func (s *AboutService) UpdateAbout(
	id string,
	title *string,
	image *string,
	imageSub *string,
	cv *string,
	birthday *string,
	city *string,
	study *string,
	website *string,
	phone *string,
	age *string,
	interests *string,
	degree *string,
	x *string,
	mail *string,
	done *int,
	projectDone *string,
	userH *int,
	hapyUser *string,
	great *int,
	greatReviews *string,
	team *int,
	supportTeam *string,
	slug *string,
	isActive *bool,
	counterActive *bool,
) (*models.About, error) {
	about, err := s.GetAboutByID(id)
	if err != nil {
		return nil, err
	}

	updates := map[string]interface{}{}
	if title != nil {
		updates["title"] = *title
	}
	if image != nil {
		updates["image"] = *image
	}
	if imageSub != nil {
		updates["image_sub"] = *imageSub
	}
	if cv != nil {
		updates["cv"] = *cv
	}
	if birthday != nil {
		updates["birthday"] = *birthday
	}
	if city != nil {
		updates["city"] = *city
	}
	if study != nil {
		updates["study"] = *study
	}
	if website != nil {
		updates["website"] = *website
	}
	if phone != nil {
		updates["phone"] = *phone
	}
	if age != nil {
		updates["age"] = *age
	}
	if interests != nil {
		updates["interests"] = *interests
	}
	if degree != nil {
		updates["degree"] = *degree
	}
	if x != nil {
		updates["x"] = *x
	}
	if mail != nil {
		updates["mail"] = *mail
	}
	if done != nil {
		updates["done"] = *done
	}
	if projectDone != nil {
		updates["project_done"] = *projectDone
	}
	if userH != nil {
		updates["user_h"] = *userH
	}
	if hapyUser != nil {
		updates["hapy_user"] = *hapyUser
	}
	if great != nil {
		updates["great"] = *great
	}
	if greatReviews != nil {
		updates["great_reviews"] = *greatReviews
	}
	if team != nil {
		updates["team"] = *team
	}
	if supportTeam != nil {
		updates["support_team"] = *supportTeam
	}
	if slug != nil {
		clean := slugifyAbout(*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 counterActive != nil {
		updates["counter_active"] = *counterActive
	}

	if len(updates) > 0 {
		if err := database.DB.Model(about).Updates(updates).Error; err != nil {
			return nil, err
		}
	}

	return s.GetAboutByID(id)
}

// DeleteAbout deletes an about entry by ID.
func (s *AboutService) DeleteAbout(id string) error {
	result := database.DB.Delete(&models.About{}, "id = ?", id)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("about not found")
	}
	return nil
}

func (s *AboutService) 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 *AboutService) slugExists(slug string, excludeID string) bool {
	var count int64
	query := database.DB.Model(&models.About{}).Where("slug = ?", slug)
	if excludeID != "" {
		query = query.Where("id <> ?", excludeID)
	}
	query.Count(&count)
	return count > 0
}

func slugifyAbout(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 "about"
	}
	return clean
}
