package services

import (
	"context"
	"errors"
	"fmt"
	"time"

	"veza-backend-api/internal/models"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// PermissionService gère les permissions
type PermissionService struct {
	db *gorm.DB
}

// NewPermissionService crée un nouveau service de permissions
func NewPermissionService(db *gorm.DB) *PermissionService {
	return &PermissionService{db: db}
}

// GetPermissions récupère toutes les permissions
func (s *PermissionService) GetPermissions(ctx context.Context) ([]models.Permission, error) {
	var permissions []models.Permission
	if err := s.db.WithContext(ctx).Find(&permissions).Error; err != nil {
		return nil, fmt.Errorf("failed to get permissions: %w", err)
	}
	return permissions, nil
}

// GetPermission récupère une permission par son ID
func (s *PermissionService) GetPermission(ctx context.Context, permissionID uuid.UUID) (*models.Permission, error) {
	var permission models.Permission
	if err := s.db.WithContext(ctx).First(&permission, permissionID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("permission not found")
		}
		return nil, fmt.Errorf("failed to get permission: %w", err)
	}
	return &permission, nil
}

// CreatePermission crée une nouvelle permission
func (s *PermissionService) CreatePermission(ctx context.Context, permission *models.Permission) error {
	if err := s.db.WithContext(ctx).Create(permission).Error; err != nil {
		return fmt.Errorf("failed to create permission: %w", err)
	}
	return nil
}

// AssignPermissionToRole assigne une permission à un rôle
func (s *PermissionService) AssignPermissionToRole(ctx context.Context, roleID, permissionID uuid.UUID) error {
	rolePermission := &models.RolePermission{
		RoleID:       roleID,
		PermissionID: permissionID,
	}
	if err := s.db.WithContext(ctx).Create(rolePermission).Error; err != nil {
		return fmt.Errorf("failed to assign permission: %w", err)
	}
	return nil
}

// RevokePermissionFromRole révoque une permission d'un rôle
func (s *PermissionService) RevokePermissionFromRole(ctx context.Context, roleID, permissionID uuid.UUID) error {
	result := s.db.WithContext(ctx).
		Where("role_id = ? AND permission_id = ?", roleID, permissionID).
		Delete(&models.RolePermission{})
	if result.Error != nil {
		return fmt.Errorf("failed to revoke permission: %w", result.Error)
	}
	if result.RowsAffected == 0 {
		return fmt.Errorf("permission assignment not found")
	}
	return nil
}

// GetRolePermissions récupère toutes les permissions d'un rôle
func (s *PermissionService) GetRolePermissions(ctx context.Context, roleID uuid.UUID) ([]models.Permission, error) {
	var permissions []models.Permission
	if err := s.db.WithContext(ctx).
		Table("permissions").
		Joins("JOIN role_permissions ON permissions.id = role_permissions.permission_id").
		Where("role_permissions.role_id = ?", roleID).
		Find(&permissions).Error; err != nil {
		return nil, fmt.Errorf("failed to get role permissions: %w", err)
	}
	return permissions, nil
}

// HasRole vérifie si un utilisateur a un rôle spécifique
func (s *PermissionService) HasRole(ctx context.Context, userID uuid.UUID, roleName string) (bool, error) {
	var count int64
	err := s.db.WithContext(ctx).Table("user_roles").
		Joins("JOIN roles ON user_roles.role_id = roles.id").
		Where("user_roles.user_id = ? AND roles.name = ?", userID, roleName).
		Where("user_roles.is_active = ?", true).
		Where("user_roles.expires_at IS NULL OR user_roles.expires_at > ?", time.Now()).
		Count(&count).Error
	if err != nil {
		return false, fmt.Errorf("failed to check role: %w", err)
	}
	return count > 0, nil
}

// HasPermission vérifie si un utilisateur a une permission spécifique
func (s *PermissionService) HasPermission(ctx context.Context, userID uuid.UUID, permissionName string) (bool, error) {
	var count int64
	err := s.db.WithContext(ctx).Table("user_roles").
		Joins("JOIN role_permissions ON user_roles.role_id = role_permissions.role_id").
		Joins("JOIN permissions ON role_permissions.permission_id = permissions.id").
		Where("user_roles.user_id = ? AND permissions.name = ?", userID, permissionName).
		Where("user_roles.is_active = ?", true).
		Where("user_roles.expires_at IS NULL OR user_roles.expires_at > ?", time.Now()).
		Count(&count).Error
	if err != nil {
		return false, fmt.Errorf("failed to check permission: %w", err)
	}
	return count > 0, nil
}
