// internal/services/user_service.go
package services

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

	"gorm.io/gorm"
)

type UserService struct {
	db           *gorm.DB  // ✅ Tambahkan ini
	userRepo     *repositories.UserRepository
	roleRepo     *repositories.RoleRepository
	auditLogRepo *repositories.AuditLogRepository
}

func NewUserService(db *gorm.DB) *UserService {
	return &UserService{
		db:           db,  // ✅ Tambahkan ini
		userRepo:     repositories.NewUserRepository(db),
		roleRepo:     repositories.NewRoleRepository(db),
		auditLogRepo: repositories.NewAuditLogRepository(db),
	}
}

// UpdateProfileRequest represents profile update data
type UpdateProfileRequest struct {
	Name  string `json:"name"`
	Phone string `json:"phone"`
	NRP   string `json:"nrp"`
}

// ChangePasswordRequest represents password change data
type ChangePasswordRequest struct {
	OldPassword string `json:"old_password" binding:"required"`
	NewPassword string `json:"new_password" binding:"required,min=6"`
}

// GetProfile gets user profile
func (s *UserService) GetProfile(userID uint) (*models.User, error) {
	return s.userRepo.FindByID(userID)
}

// UpdateProfile - TANPA enkripsi
func (s *UserService) UpdateProfile(userID uint, req UpdateProfileRequest, ipAddress, userAgent string) (*models.User, error) {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return nil, err
	}

	// Update fields
	if req.Name != "" {
		user.Name = req.Name
	}
	
	// ✅ Update phone TANPA enkripsi
	if req.Phone != "" {
		user.Phone = req.Phone
	}
	
	// ✅ Update NRP TANPA enkripsi
	if req.NRP != "" {
		// Check if NRP already exists for another user
		existingNRP, _ := s.userRepo.FindByNRP(req.NRP)
		if existingNRP != nil && existingNRP.ID != userID {
			return nil, errors.New("NRP already used by another user")
		}
		user.NRP = req.NRP
	}

	if err := s.userRepo.Update(user); err != nil {
		return nil, errors.New("failed to update profile")
	}

	// Log audit
	s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityUser, &userID, 
		"Profile updated", ipAddress, userAgent)

	return user, nil
}

// ChangePassword changes user password
func (s *UserService) ChangePassword(userID uint, req ChangePasswordRequest, ipAddress, userAgent string) error {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return err
	}

	// Verify old password
	if !utils.CheckPasswordHash(req.OldPassword, user.Password) {
		return errors.New("invalid old password")
	}

	// Hash new password
	hashedPassword, err := utils.HashPassword(req.NewPassword)
	if err != nil {
		return errors.New("failed to hash password")
	}

	user.Password = hashedPassword
	if err := s.userRepo.Update(user); err != nil {
		return errors.New("failed to change password")
	}

	// Log audit
	s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityUser, &userID, 
		"Password changed", ipAddress, userAgent)

	return nil
}

// GetUserStats gets user statistics
func (s *UserService) GetUserStats(userID uint) (map[string]interface{}, error) {
    stats := make(map[string]interface{})

    // ✅ Count items reported by user
    var itemCount int64
    if err := s.db.Model(&models.Item{}).  // ← Ganti dari s.userRepo.db
        Where("reporter_id = ? AND deleted_at IS NULL", userID).
        Count(&itemCount).Error; err != nil {
        return nil, err
    }
    stats["items_reported"] = itemCount

    // ✅ Count lost items reported
    var lostItemCount int64
    if err := s.db.Model(&models.LostItem{}).  // ← Ganti dari s.userRepo.db
        Where("user_id = ? AND deleted_at IS NULL", userID).
        Count(&lostItemCount).Error; err != nil {
        return nil, err
    }
    stats["lost_items_reported"] = lostItemCount

    // ✅ Count claims made
    var claimCount int64
    if err := s.db.Model(&models.Claim{}).  // ← Ganti dari s.userRepo.db
        Where("user_id = ? AND deleted_at IS NULL", userID).
        Count(&claimCount).Error; err != nil {
        return nil, err
    }
    stats["claims_made"] = claimCount

    // ✅ Count approved claims
    var approvedClaimCount int64
    if err := s.db.Model(&models.Claim{}).  // ← Ganti dari s.userRepo.db
        Where("user_id = ? AND status = ? AND deleted_at IS NULL", userID, models.ClaimStatusApproved).
        Count(&approvedClaimCount).Error; err != nil {
        return nil, err
    }
    stats["claims_approved"] = approvedClaimCount

    return stats, nil
}

// UpdateUserRole updates user role (admin only)
func (s *UserService) UpdateUserRole(adminID, userID, roleID uint, ipAddress, userAgent string) error {
	// Verify role exists
	role, err := s.roleRepo.FindByID(roleID)
	if err != nil {
		return errors.New("invalid role")
	}

	// Update role
	if err := s.userRepo.UpdateRole(userID, roleID); err != nil {
		return errors.New("failed to update user role")
	}

	// Log audit
	s.auditLogRepo.Log(&adminID, models.ActionUpdate, models.EntityUser, &userID, 
		"Role updated to: "+role.Name, ipAddress, userAgent)

	return nil
}

// BlockUser blocks a user (admin only)
func (s *UserService) BlockUser(adminID, userID uint, ipAddress, userAgent string) error {
	// Cannot block self
	if adminID == userID {
		return errors.New("cannot block yourself")
	}

	if err := s.userRepo.BlockUser(userID); err != nil {
		return errors.New("failed to block user")
	}

	// Log audit
	s.auditLogRepo.Log(&adminID, models.ActionBlock, models.EntityUser, &userID, 
		"User blocked", ipAddress, userAgent)

	return nil
}

// UnblockUser unblocks a user (admin only)
func (s *UserService) UnblockUser(adminID, userID uint, ipAddress, userAgent string) error {
	if err := s.userRepo.UnblockUser(userID); err != nil {
		return errors.New("failed to unblock user")
	}

	// Log audit
	s.auditLogRepo.Log(&adminID, models.ActionUnblock, models.EntityUser, &userID, 
		"User unblocked", ipAddress, userAgent)

	return nil
}

// DeleteUser deletes a user (admin only)
func (s *UserService) DeleteUser(adminID, userID uint, ipAddress, userAgent string) error {
	// Cannot delete self
	if adminID == userID {
		return errors.New("cannot delete yourself")
	}

	if err := s.userRepo.Delete(userID); err != nil {
		return errors.New("failed to delete user")
	}

	// Log audit
	s.auditLogRepo.Log(&adminID, models.ActionDelete, models.EntityUser, &userID, 
		"User deleted", ipAddress, userAgent)

	return nil
}

func (s *UserService) GetAllUsers(page, limit int) ([]models.User, int64, error) {
    return s.userRepo.FindAll(page, limit)
}

// GetUserByID gets user by ID
func (s *UserService) GetUserByID(userID uint) (*models.User, error) {
    return s.userRepo.FindByID(userID)
}