// internal/repositories/user_repo.go - FIXED for ENCRYPTED NRP
package repositories

import (
	"errors"
	"lost-and-found/internal/models"

	"gorm.io/gorm"
)

type UserRepository struct {
	db *gorm.DB
}

func NewUserRepository(db *gorm.DB) *UserRepository {
	return &UserRepository{db: db}
}

func (r *UserRepository) Create(user *models.User) error {
	return r.db.Create(user).Error
}

func (r *UserRepository) FindByID(id uint) (*models.User, error) {
	var user models.User
    // ✅ Tambahkan .Preload("Role.Permissions")
	err := r.db.Preload("Role").Preload("Role.Permissions").First(&user, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("user not found")
		}
		return nil, err
	}
	return &user, nil
}

func (r *UserRepository) FindByEmail(email string) (*models.User, error) {
	var user models.User
	// ✅ UPDATE: Preload Role DAN Role.Permissions
	err := r.db.
		Preload("Role").
		Preload("Role.Permissions"). // Memuat daftar hak akses
		Where("email = ?", email).
		First(&user).Error

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("user not found")
		}
		return nil, err
	}
	return &user, nil
}

// ✅ FIXED: FindByNRP now accepts ENCRYPTED NRP
func (r *UserRepository) FindByNRP(nrp string) (*models.User, error) {
	var user models.User
	// ✅ UPDATE: Preload Role DAN Role.Permissions
	err := r.db.
		Preload("Role").
		Preload("Role.Permissions"). // Memuat daftar hak akses
		Where("nrp = ?", nrp).
		First(&user).Error

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil // Return nil jika tidak ditemukan (bukan error sistem)
		}
		return nil, err
	}
	return &user, nil
}
func (r *UserRepository) FindAll(page, limit int) ([]models.User, int64, error) {
	var users []models.User
	var total int64

	if err := r.db.Model(&models.User{}).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (page - 1) * limit
	err := r.db.
		Preload("Role"). // Cukup Role saja untuk list view
		Order("created_at DESC").
		Offset(offset).Limit(limit).
		Find(&users).Error

	if err != nil {
		return nil, 0, err
	}

	return users, total, nil
}
func (r *UserRepository) Update(user *models.User) error {
	return r.db.Save(user).Error
}

func (r *UserRepository) UpdateRole(userID, roleID uint) error {
	return r.db.Model(&models.User{}).Where("id = ?", userID).Update("role_id", roleID).Error
}

func (r *UserRepository) UpdateStatus(userID uint, status string) error {
	return r.db.Model(&models.User{}).Where("id = ?", userID).Update("status", status).Error
}

func (r *UserRepository) Delete(id uint) error {
	return r.db.Delete(&models.User{}, id).Error
}

func (r *UserRepository) BlockUser(id uint) error {
	return r.UpdateStatus(id, "blocked")
}

func (r *UserRepository) UnblockUser(id uint) error {
	return r.UpdateStatus(id, "active")
}

func (r *UserRepository) CountByRole(roleID uint) (int64, error) {
	var count int64
	err := r.db.Model(&models.User{}).Where("role_id = ?", roleID).Count(&count).Error
	return count, err
}

func (r *UserRepository) GetUserStats(userID uint) (map[string]interface{}, error) {
    var stats map[string]interface{} = make(map[string]interface{})

    // Items reported
    var itemCount int64
    if err := r.db.Model(&models.Item{}).
        Where("reporter_id = ?", userID).Count(&itemCount).Error; err != nil {
        return nil, err
    }
    stats["items_reported"] = itemCount

    // Lost items
    var lostItemCount int64
    if err := r.db.Model(&models.LostItem{}).
        Where("user_id = ?", userID).Count(&lostItemCount).Error; err != nil {
        return nil, err
    }
    stats["lost_items_reported"] = lostItemCount

    // Claims
    var claimCount int64
    if err := r.db.Model(&models.Claim{}).
        Where("user_id = ?", userID).Count(&claimCount).Error; err != nil {
        return nil, err
    }
    stats["claims_made"] = claimCount

    // Approved claims
    var approvedClaimCount int64
    if err := r.db.Model(&models.Claim{}).
        Where("user_id = ? AND status = ?", userID, models.ClaimStatusApproved).
        Count(&approvedClaimCount).Error; err != nil {
        return nil, err
    }
    stats["claims_approved"] = approvedClaimCount

    return stats, nil
}