package services

import (
	"strings"

	"trustcontact/internal/models"
	"trustcontact/internal/repo"

	"gorm.io/gorm"
)

type UsersService struct {
	users *repo.UserRepo
}

type UsersQuery struct {
	Q        string
	Sort     string
	Dir      string
	Page     int
	PageSize int
}

type UsersPage struct {
	Users      []models.User
	Total      int64
	Page       int
	PageSize   int
	TotalPages int
	HasPrev    bool
	HasNext    bool
	PrevPage   int
	NextPage   int
	Sort       string
	Dir        string
	Q          string
}

func NewUsersService(database *gorm.DB) *UsersService {
	return &UsersService{users: repo.NewUserRepo(database)}
}

func (s *UsersService) List(query UsersQuery) (*UsersPage, error) {
	page := query.Page
	if page < 1 {
		page = 1
	}
	pageSize := query.PageSize
	if pageSize <= 0 {
		pageSize = 10
	}
	if pageSize > 500 {
		pageSize = 500
	}

	sort := normalizeSort(query.Sort)
	dir := normalizeDir(query.Dir)

	users, total, err := s.users.List(repo.UserListParams{
		Query:    strings.TrimSpace(query.Q),
		Sort:     sort,
		Dir:      dir,
		Page:     page,
		PageSize: pageSize,
	})
	if err != nil {
		return nil, err
	}

	totalPages := 0
	if total > 0 {
		totalPages = int((total + int64(pageSize) - 1) / int64(pageSize))
	}
	if totalPages > 0 && page > totalPages {
		page = totalPages
		users, total, err = s.users.List(repo.UserListParams{
			Query:    strings.TrimSpace(query.Q),
			Sort:     sort,
			Dir:      dir,
			Page:     page,
			PageSize: pageSize,
		})
		if err != nil {
			return nil, err
		}
	}

	hasPrev := page > 1
	hasNext := totalPages > 0 && page < totalPages

	return &UsersPage{
		Users:      users,
		Total:      total,
		Page:       page,
		PageSize:   pageSize,
		TotalPages: totalPages,
		HasPrev:    hasPrev,
		HasNext:    hasNext,
		PrevPage:   max(1, page-1),
		NextPage:   page + 1,
		Sort:       sort,
		Dir:        dir,
		Q:          strings.TrimSpace(query.Q),
	}, nil
}

func (s *UsersService) GetByID(id string) (*models.User, error) {
	return s.users.FindByID(id)
}

func normalizeSort(sort string) string {
	switch strings.ToLower(strings.TrimSpace(sort)) {
	case "id", "name", "email":
		return strings.ToLower(strings.TrimSpace(sort))
	default:
		return "id"
	}
}

func normalizeDir(dir string) string {
	if strings.ToLower(strings.TrimSpace(dir)) == "desc" {
		return "desc"
	}
	return "asc"
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
