package repository

import (
	"errors"
	"strings"

	"gorm.io/gorm"
	"hyapp-admin-server/internal/model"
)

func normalizePermission(permission model.Permission) (model.Permission, error) {
	permission.Name = strings.TrimSpace(permission.Name)
	permission.Code = strings.TrimSpace(permission.Code)
	permission.Kind = strings.TrimSpace(permission.Kind)
	permission.Description = strings.TrimSpace(permission.Description)
	if permission.Name == "" || permission.Code == "" {
		return permission, errors.New("permission name and code are required")
	}
	if !validPermissionKind(permission.Kind) {
		return permission, errors.New("invalid permission kind")
	}
	return permission, nil
}

func normalizeMenu(menu model.Menu) (model.Menu, error) {
	menu.Title = strings.TrimSpace(menu.Title)
	menu.Code = strings.TrimSpace(menu.Code)
	menu.Path = strings.TrimSpace(menu.Path)
	menu.Icon = strings.TrimSpace(menu.Icon)
	menu.PermissionCode = strings.TrimSpace(menu.PermissionCode)
	if menu.Title == "" || menu.Code == "" {
		return menu, errors.New("menu title and code are required")
	}
	return menu, nil
}

func applyUserFilters(query *gorm.DB, options ListOptions) *gorm.DB {
	if keyword := strings.TrimSpace(options.Keyword); keyword != "" {
		like := "%" + keyword + "%"
		query = query.Joins("LEFT JOIN admin_teams user_team ON user_team.id = admin_users.team_id").
			Where("username LIKE ? OR admin_users.name LIKE ? OR admin_users.team LIKE ? OR user_team.name LIKE ?", like, like, like, like)
	}
	if status := strings.TrimSpace(options.Status); status != "" && status != "all" {
		query = query.Where("admin_users.status = ?", status)
	}
	if len(options.TeamIDs) > 0 {
		query = query.Where("admin_users.team_id IN ?", options.TeamIDs)
	} else if options.TeamID > 0 {
		query = query.Where("admin_users.team_id = ?", options.TeamID)
	}
	if role := strings.TrimSpace(options.Role); role != "" && role != "全部角色" && role != "all" {
		query = query.Joins("JOIN admin_user_roles aur ON aur.user_id = admin_users.id").
			Joins("JOIN admin_roles ar ON ar.id = aur.role_id").
			Where("ar.name = ? OR ar.code = ?", role, role)
	}
	return query
}

func applyUserDataAccess(query *gorm.DB, access DataAccess) *gorm.DB {
	if access.All || !access.Restricted {
		return query
	}
	conditions := make([]string, 0, 2)
	args := make([]any, 0, 2)
	if len(access.Teams) > 0 {
		conditions = append(conditions, "admin_users.team IN ?")
		args = append(args, access.Teams)
	}
	if access.SelfOnly || len(access.Teams) == 0 {
		conditions = append(conditions, "admin_users.id = ?")
		args = append(args, access.UserID)
	}
	return query.Where(strings.Join(conditions, " OR "), args...)
}

func replaceUserRoles(tx *gorm.DB, user *model.User, roleIDs []uint) error {
	var roles []model.Role
	if len(roleIDs) > 0 {
		if err := tx.Where("id IN ?", roleIDs).Find(&roles).Error; err != nil {
			return err
		}
	}
	return tx.Model(user).Association("Roles").Replace(roles)
}

func normalizePage(page int, pageSize int) (int, int) {
	if page < 1 {
		page = 1
	}
	if pageSize < 1 {
		pageSize = 10
	}
	if pageSize > 100 {
		pageSize = 100
	}
	return page, pageSize
}

func userSort(sort string) string {
	switch sort {
	case "username_asc":
		return "admin_users.username ASC"
	case "username_desc":
		return "admin_users.username DESC"
	case "last_login_desc":
		return "admin_users.last_login_at_ms DESC"
	default:
		return "admin_users.id ASC"
	}
}

func validUserStatus(status string) bool {
	return status == model.UserStatusActive || status == model.UserStatusLocked || status == model.UserStatusDisabled
}

func validPermissionKind(kind string) bool {
	return kind == "menu" || kind == "button" || kind == "api"
}

func permissionSet(codes []string) map[string]struct{} {
	set := map[string]struct{}{}
	for _, code := range codes {
		set[code] = struct{}{}
	}
	return set
}
