<?php

namespace App\Modules\Adldap;

use App\Facades\DBconfig;
use adLDAP\adLDAP as Ldap;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;

class Adldap
{
    public function auth($username, $password, array $settings = [])
    {
        try {
            // Sanitize username and password to handle special characters
            $username = trim($username);
            $password = trim($password);
            
            // Log authentication attempt (without sensitive data)
            Log::info('LDAP authentication attempt', [
                'username' => $username,
                'password_length' => strlen($password),
                'has_special_chars' => preg_match('/[&%#<>"\']/', $password) ? 'yes' : 'no'
            ]);
            
            // Merge the settings array
            // Just to document it uses the Settings table!
            $settings = array_replace(DBconfig::get('ldap', []), $settings);
            
            // Validate required LDAP settings
            if (!$this->validateLdapSettings($settings)) {
                Log::error('LDAP authentication failed - missing required settings', ['username' => $username]);
                return false;
            }
            
            // Safely handle domain_controllers - ensure it exists and is an array
            if (isset($settings['domain_controllers']) && is_array($settings['domain_controllers'])) {
                $settings['domain_controllers'] = Arr::pluck($settings['domain_controllers'], 'id');
            } else {
                Log::error('LDAP authentication failed - domain_controllers not properly configured', ['username' => $username]);
                return false;
            }

            // $settings["admin_username"] = DBconfig::get('ldap.admin_username');
            // $settings["admin_password"] = DBconfig::get('ldap.admin_password');

            $ldap = new Ldap($settings);

            // Try to authenticate the user
            $authSuccess = $ldap->user()->authenticate($username, $password);

            if (! $authSuccess) {
                Log::info('LDAP authentication failed - invalid credentials', ['username' => $username]);
                return false;
            }

            // Retrieve the details for the user
            $user = $ldap->user()->info($username, ['memberof', 'displayname', 'mail', 'firstname']);

            // By default, it returns an array, so we want to fetch the first user
            $userInfo = $user[0];

            // Format the results in a more usable way
            $userFormatted = [
                'name'   => $userInfo['displayname'][0],
                'email'  => isset($userInfo['mail']) ? $userInfo['mail'][0] : '',
                'groups' => $userInfo['memberof'],
                'dn'     => $userInfo['dn'],
            ];

            Log::info('LDAP authentication successful', ['username' => $username, 'email' => $userFormatted['email']]);
            return $userFormatted;
            
        } catch (\Exception $e) {
            Log::error('LDAP authentication exception', [
                'username' => $username,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return false;
        }
    }
    
    /**
     * Validate that required LDAP settings are present
     * 
     * @param array $settings
     * @return bool
     */
    private function validateLdapSettings($settings)
    {
        $requiredSettings = ['domain_controllers', 'account_suffix', 'base_dn'];
        
        foreach ($requiredSettings as $setting) {
            if (!isset($settings[$setting]) || empty($settings[$setting])) {
                Log::error('Missing required LDAP setting', ['setting' => $setting]);
                return false;
            }
        }
        
        return true;
    }
}