<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
use Cake\I18n\FrozenDate;
use Cake\I18n\FrozenTime;
use Cake\ORM\Entity;

// Activer Stats via src/Routing/Filter/SessionTimeoutFilter.php
const SessionTimeoutON = false;
//const SessionTimeoutON = true;



/**
 * Users Controller
 *
 * @property \App\Model\Table\UsersTable $Users
 */
class UsersController extends AppController {


    // Idem Model/Table/LdapConnectionsTable
    const DEFAULT_AUTH_TYPE = 'uid';
    
    /*
    // Nom affichable pour cette entité
    // @Override
    public function getNiceName() { return "utilisateur"; }
    */
    // Nom pluriel affichable pour cette entité
    //@Override
    public function getTypeNamePlural($alias_controller_name=null) {
        //return strtolower($this->name);
        //return strtolower($this->getName());
        if ($alias_controller_name == 'ChefSciences') return 'responsables scientifiques (PI)';
        if ($alias_controller_name == 'ChefProjets') return 'chefs de projet';
        return 'utilisateurs';
    }
    
    
    // "l'" utilisateur (et non pas "le utilisateur")
    // @deprecated
    // @override parent
    public function getArticle() { return "L'"; }
    
    public $paginate = [
        'contain' => [
            'GroupesMetiers',
            'GroupesThematiques',
            'SurCategories'
        ],
        'limit' => 20,
        'order' => [
            'Users.nom' => 'asc'
        ]
    ];
    
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Paginator');
        
        // déplacé dans beforeFilter()
        //$this->Auth->allow(['logout']);

        // Pour autoriser le SIGNUP des nouveaux utilisateurs
        //$this->Auth->allow(['logout', 'add']);
    }
    
    
    // 1) AVANT connexion
    public function beforeFilter(Event $event)
    {
        parent::beforeFilter($event);
        $this->LdapAuth->allow(['logout']);
    }

    
    /*
     * @Override
     *
     * Initialisation des autorisations pour les actions spécifiques à ce controleur
     *
     */
    protected function setAuthorizations() {
        
        
        /*
         * a) Noms et verbes à utiliser (surtout dans les notifications) pour les actions
         *
         */
        $this->setActionsNounAndPastVerb([
            'login' => ['Connexion','connecté'],
            'logout' => ['Déconnexion','déconnecté'],
        ]);
        
        
        /*
         * b) Actions de ce controleur qui enverront des notifications (log et/ou email)
         *
         * 'log' = logger seulement
         * 'mail' => envoyer un mail seulement
         * 'both' = faire les 2 (logger ET envoyer un mail)
         *
         */
        $this->setNotificationAllowedOnActions([
            'login' => 'log',
            
            // Ne marchera pas car pas d'utilisateur en session
            //'logout' => 'log',
            
            'add' => 'log',
            'edit' => 'log',
            'delete' => 'log',
            // ...
        ]);
        
        
        /*
         * c) Règles d'accès (ACLs)
         *
         */
        
        // Actions autorisées à tous
        foreach (['login', 'logout', 'getLdapLogin', 'getLdapEmail', 'indexRecap'] as $action) 
            $this->setAuthorizationsForAction($action, 0);
        
        // Action autorisées seulement à superadmin
        // TODO: affiner dans le cas d'un LDAP : même superadmin ne doit pas pouvoir supprimer ou modifier (sauf certains attributs) un utilisateur 
        foreach (['add', 'edit', 'delete'] as $action) 
            $this->setAuthorizationsForAction($action, -1, ['super'=>0]);
        
    } // setAuthorizations
    
    
    
    
    // 2) APRES connexion
    /**
     * Give authorization for users
     * 
     * @param
     *            $user
     * @return boolean
     */
    /*
    public function isAuthorized($user,
        $action=null, $id=null, $role=null, $userCname=null) {
        // $configuration = $this->confLabinvent;
        // $role = $this->Users->find()->where(['username' => $user[$configuration->authentificationType_ldap][0]])->first()['role'];
        // $action = $this->request->getAttribute('params')['action'];
        $action = $this->getActionPassed();
        
        // Actions de CE controleur accessibles à tous les profils
        // if (in_array($action, ['index', 'view', 'getLdapLogin', 'getLdapEmail','indexRecap'])) return true;
        if (in_array($action, [
            'getLdapLogin',
            'getLdapEmail',
            'indexRecap'
        ]))
            return true;
        
        // Inutile car déjà dit dans parent::isAuthorized()
        // Super-Admin peut accéder à toutes les actions de CE controleur
        // if ($role == 'Super Administrateur') return true;
        
        // Par défaut refuser
        // return false;
        return parent::isAuthorized($user);
    }
    */

    // ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#identifier-les-utilisateurs-et-les-connecter
    public function login()
    {
        $this->myDebug("step 2: UsersController.login()");
        
        // Un utilisateur a essayé de se loguer
        if ($this->request->is('post')) {
            // Identification du user en utilisant les données POST
            // - sans LDAP
            //$user = $this->Auth->identify();
            // - avec LDAP (ou fake ldap)
            $user = $this->LdapAuth->connection();
            //var_dump($user);
            //debug($user);
            
            //if ($user) {
            if ($user === FALSE)             
                // Utilisateur non reconnu
                $this->Flash->error(__('Login ou mot de passe invalide, réessayez'));
                
            else {
                // Le login a été accepté 
                // Sauvegarde le user dans la session
                //$this->Auth->setUser($user);
                $this->LdapAuth->setUser($user);
                
                //debug($user);
                /* Voici ce que contient $user :
                [
                	'sn' => [
                		(int) 0 => 'Pallier'
                	],
                	'mail' => [
                		(int) 0 => 'Etienne.Pallier@irap.omp.eu'
                	],
                	'givenname' => [
                		(int) 0 => 'Etienne'
                	],
                	'uid' => [
                		(int) 0 => 'epallier'
                	],
                	'userpassword' => [
                		(int) 0 => 'mot-de-passe-crypté'
                	]
                ]
                */
                
                ///if (SessionTimeoutON)
                $this->statsUpdateForCurrentUserWhen(null,'sur login');
                //$this->statsUpdateForCurrentUserOnLogin();
                //exit;
                
                // On va maintenant à la page qui etait demandée
                //return $this->redirect($this->Auth->redirectUrl());
                return $this->redirect($this->LdapAuth->redirectUrl());
            }
            
        } // POST
    } // login()
    

    public function logout() {
        //debug($this->u);
        // L'action logout ne passe pas par afterFilter(),
        // et donc il faut la traiter explicitement...
        ////if (SessionTimeoutON)
        // Si user PAS déjà logout, on enregistre sa stat 
        if ($this->LdapAuth->user())
            $this->statsUpdateForCurrentUserWhen(null,'sur logout');
        //$this->statsUpdateForCurrentUserOnLogout();
        //$this->Flash->success('You are now logged out.');
        return $this->redirect($this->LdapAuth->logout());
        // Puis ça va sur /users/login
    }
    
    
    /*
     * Renvoie les infos de l'utilisateur qui sont dans la session
     * 
     * Voici ce que contient $_SESSION['Auth']['User'] par exemple :
    [
        'sn' => [
            (int) 0 => 'Pallier'
        ],
        'mail' => [
            (int) 0 => 'Etienne.Pallier@irap.omp.eu'
        ],
        'givenname' => [
            (int) 0 => 'Etienne'
        ],
        'uid' => [
            (int) 0 => 'epallier'
        ],
        'userpassword' => [
            (int) 0 => 'mot-de-passe-crypté'
        ]
    ]
     */
    private function _getCurrentUserInfosFromSession() {
        // Current user infos
        return isset($_SESSION['Auth']['User']) ? $_SESSION['Auth']['User'] : [];
    }
    private function _getCurrentUserFullNameFromSession($user_infos = null) {
        if (!$user_infos) $user_infos = $this->_getCurrentUserInfosFromSession();
        //debug($user_infos);
        // "Pallier Etienne"
        return $user_infos ? $user_infos['sn'][0].' '.$user_infos['givenname'][0] : 'Name Firstname';
    }
    private function _getCurrentUserLoginFromSession($user_infos = null) {
        if (!$user_infos) $user_infos = $this->_getCurrentUserInfosFromSession();
        if (! $user_infos) throw new \ErrorException("Pas d'utilisateur défini dans la session !!!");
        //debug($user_infos);
        // "Pallier Etienne"
        //$user_login_field_name = $this->authenticationType;
        //$user_login_field_name = isset($user_infos['uid']) ? 'uid' : 'samaccountname';
        $user_login_field_name = isset($user_infos[self::DEFAULT_AUTH_TYPE]) ? self::DEFAULT_AUTH_TYPE : 'samaccountname';
        if (! isset($user_infos[$user_login_field_name])) {
            debug($user_login_field_name);
            debug($user_infos);
            throw new \ErrorException("La variable $user_infos ne contient pas le user login (ni champ 'uid' ni champ 'samaccountname')");
        }
        //return $user_infos ? $user_infos[$user_login_field_name][0] : 'user_login';
        return $user_infos[$user_login_field_name][0];
    }
    private function _getCurrentUserEntityFromSession_ORIG($session_user = null) {
        $user_fullname = $this->_getCurrentUserFullNameFromSession($session_user);
        //debug("user_fullname:"); debug($user_fullname);
        // "Pallier Etienne"
        
        return $this->Users->find()->where(['nom'=>$user_fullname])->first();
    }
    private function _getCurrentUserEntityFromSession($session_user = null) {
        $user_login = $this->_getCurrentUserLoginFromSession($session_user);
        return $this->Users->find()->where(['username'=>$user_login])->first();
    }
    
    
    /*
     * Mise à jour des stats pour le user courant ($user_infos) (et pour l'année courante) 
     * au moment de l'événement $event_name
     */
    public function statsUpdateForCurrentUserWhen($session_user=null, $event_name) {
        $user_id = ($event_name=='sur logout') ? $this->u->id : $this->_getCurrentUserEntityFromSession($session_user)->id;
        //debug($user);
        $this->Users->Stats->updateForUserWhen($user_id, $event_name);
    }

    
    /**
     * Index method
     *
     * @return \Cake\Network\Response|null
     */
    public function index() {
        
        $filtre = $this->request->getQuery('filtre');
        //debug($this->viewVars);
        
        // Si on est sur l'instance de l'IRAP (InventIrap),
        // on affiche l'url vers la page de l'ANNUAIRE du site web du labo
        $lab_website_urls = ($this->confLabinvent->labNameShort != 'IRAP') ? [] : [
            "Annuaire IRAP" => 'https://www.irap.omp.eu/annuaire',
            "Annuaire IRAP (OMP)" => 'http://ezomp2.omp.obs-mip.fr/annuaire/annuaire-irap2',
        ];
        
        //$priviledgedUsers = $this->Users->find()->where(['role !=' => 'Utilisateur']);
        
        /*
        $this->paginate = [
            'contain' => [
                'GroupesMetiers',
                'GroupesThematiques',
                'SurCategories'
            ],
            'limit' => 12,
            'order' => [
                'Users.nom' => 'asc'
            ]
        ];
        */
        
        $this->paginate = [
            'contain' => [
                'GroupesMetiers',
                'GroupesThematiques',
                'SurCategories'
            ],
            'sortWhitelist' => [
                'nom',
                'email',
                'role',
                'GroupesThematiques.nom',
                'GroupesMetiers.nom',
                'SurCategories.nom',
            ],
            'limit' => 20,
            /*
            'order' => [
                'Users.nom' => 'asc'
            ]
            */
        ];
        
        $conditions = $filtre ? ['role =' => 'Responsable'] : [];
        $entities = $this->paginate($this->Users->find('all', [
            'conditions' => $conditions
        ]));
        // ALL users
        //$entities = $this->paginate();
        // ce qui revient au même que :
        //$users = $this->paginate($this->Users);
        // Only priviledged users
        //$users = $this->paginate($priviledgedUsers);
        
        // Affichage informations disponible pour l'utilisateur connecté
        $this->myDebug($this->LdapAuth->user());
        
        //////$this->set('nbUsers', $this->Users->find()->count());
        //$this->set('nbUsers', $this->Users->find('all')->count());
        //$this->set('nbUsers', $priviledgedUsers->count());
        
        $this->set(compact('entities', 'lab_website_urls', 'filtre'));
        /* Inutile si pas de JSON
        $this->set('_serialize', [
            'users'
        ]);
        */
        
    } // index()

    
    /**
     * Index_recap method
     *
     * @return \Cake\Network\Response|null
     */
    /* (EP202010 fusionnée avec index())
    public function indexRecap()
    {
        $this->paginate = [
            'contain' => [
                'GroupesMetiers',
                'GroupesThematiques',
                'SurCategories'
            ],
            'sortWhitelist' => [
                'nom',
                'email',
                'GroupesThematiques.nom',
                'GroupesMetiers.nom',
                'SurCategories.nom',
            ],
        ];
        
        $entities = $this->paginate($this->Users->find('all', [
            'conditions' => [
                'role =' => 'Responsable'
            ]
        ]));
        
        // Affichage informations disponible pour l'utilisateur connecté
        $this->myDebug($this->LdapAuth->user());
        
        /S
        $this->set('nbUsers', $this->Users->find('all', [
            'conditions' => [
                'role =' => 'Responsable'
            ]
        ])
        ->count());
        S/
            
        $this->set(compact('entities'));
        /S Uniquement pour JSON
        $this->set('_serialize', [
            'users'
        ]);
        S/
    }
    */
    

    /**
     * View method
     *
     * @param string|null $id
     *            User id.
     * @return \Cake\Network\Response|null
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function view($id = null)
    {
        $user = $this->Users->get($id, [
            'contain' => [
                'GroupesMetiers',
                'GroupesThematiques',
                'SurCategories'
            ]
        ]);
        
        $this->set('user', $user);
        $this->set('_serialize', [
            'user'
        ]);
    }


    
    /**
     * Add method
     *
     * @return \Cake\Network\Response|void Redirects on successful add, renders view otherwise.
     */
    public function add()
    {
        // Création d'un objet User VIDE avec tous les champs
        $user = $this->Users->newEntity();
        
        // (POST) Un user vient d'être créé, on le sauve en BD, 
        // puis on va sur la vue individuelle de ce nouveau user
        if ($this->request->is('post')) {
            $user = $this->Users->patchEntity($user, $this->request->getData());
            if ($this->Users->save($user)) {
                $this->Flash->success(__('L\'utilisateur a bien été ajouté.'));
                // On va maintenant à la vue individuelle de ce nouvel utilisateur
                return $this->redirect([
                    'action' => 'view',
                    $user->id
                ]);
            } else {
                $this->Flash->error(__('L\'utilisateur n\'a pas pu être ajouté.'));
            }
        }
        
        // (pas POST) Ici, on vient sur la vue d'ajout (add.ctp) pour la première fois 
        // On prépare donc quelques listes qui seront nécessaires à cette vue
        
        $groupesMetiers = $this->Users->GroupesMetiers->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        $groupesThematiques = $this->Users->GroupesThematiques->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        //->toArray();
        /* Ajoute l'élément 0 => 'N/A' en tête de tableau
         * SANS changer les clés !!!
        // 1) on ajoute un élément vide à la clé "0",
        // et on trie le tableau sur les values (nom) (en conservant les clés)
        // => l'élément vide se retrouve donc en tête
        $groupesThematiques[0] = '';
        asort($groupesThematiques);
        // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête !
        $groupesThematiques[0] = 'N/A';
         */
        
        $sur_categorie = $this->Users->SurCategories->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        
        // TODO: Refactoriser: idem pour add() et edit() (ainsi que leurs pendants dans MaterielsController)
       $this->setUsersLists();
        /*
        // On recup tous les users du LDAP (ou fakeLDAP si on n'est pas en mode LDAP)
        //$users = TableRegistry::get('LdapConnections')->getListUsers();
        //sort($users);
        $users_login_and_email = TableRegistry::getTableLocator()->get('LdapConnections')->getUsersLoginAndEmail();
        $users_name = array_keys($users_login_and_email);
        // Formatage en $users_option_list["Etienne Pallier"] = "Etienne Pallier" ...
        $users_option_list = [];
        for ($i = 0; $i < sizeof($users_name); $i ++) {
            $users_option_list[$users_name[$i]] = $users_name[$i];
        }
        */
        
        // On passe à la vue add.ctp toutes les variables créés ci-dessus 
        // "user" est l'utilisateur $user créé au début, et qui est vide
        $this->set(compact(
            'user', 
            'groupesMetiers', 
            //'users_option_list', 'users_login_and_email', 
            'groupesThematiques', 'sur_categorie'
        ));
        $this->set('_serialize', [
            'user'
        ]);
        
        // Ici, la vue add.ctp (formulaire d'ajout d'un user) est maintenant automatiquement affichée
    }

    /**
     * Edit method
     *
     * @param string|null $id
     *            User id.
     * @return \Cake\Network\Response|void Redirects on successful edit, renders view otherwise.
     * @throws \Cake\Network\Exception\NotFoundException When record not found.
     */
    public function edit($id = null)
    {
        $user = $this->Users->get($id, [
            'contain' => []
        ]);
        if ($this->request->is([
            'patch',
            'post',
            'put'
        ])) {
            //debug($this->request->getData());
            //exit;
            /*
             'username' => 'pdevoto',
             'password' => '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW',
             (from DB =    '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW')
             'email' => 'Pierre.Devoto@irap.omp.eu',
	         'role' => 'Responsable',
	         'groupes_metier_id' => '2',
	         'groupes_thematique_id' => '1',
	         'sur_categorie_id' => '1'
            */
            $user = $this->Users->patchEntity($user, $this->request->getData());
            //debug($user); exit;
            if ($this->Users->save($user)) {
                $this->Flash->success(__("L'utilisateur a bien été modifié"));
                return $this->redirect([
                    'action' => 'view',
                    $id
                ]);
            } else {
                //debug($user->getErrors());
                $this->Flash->error(__("L'utilisateur n'a pas pu être modifié"));
            }
        }
        $groupesMetiers = $this->Users->GroupesMetiers->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        $groupesThematiques = $this->Users->GroupesThematiques->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        /* Ajoute l'élément 0 => 'N/A' en tête de tableau
        ->toArray();
         * SANS changer les clés !!!
         // 1) on ajoute un élément vide à la clé "0",
         // et on trie le tableau sur les values (nom) (en conservant les clés)
         // => l'élément vide se retrouve donc en tête
         $groupesThematiques[0] = '';
         asort($groupesThematiques);
         // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête !
         $groupesThematiques[0] = 'N/A';
         */
        
        $sur_categorie = $this->Users->SurCategories->find('list', [
            'keyField' => 'id',
            'valueField' => 'nom'
        ]);
        $this->set(compact('user', 'groupesMetiers', 'groupesThematiques', 'sur_categorie'));
        $this->set('_serialize', [
            'user'
        ]);
    } // edit()

    /**
     * Delete method
     *
     * @param string|null $id
     *            User id.
     * @return \Cake\Network\Response|null Redirects to index.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function delete($id = null)
    {
        $this->request->allowMethod([
            'post',
            'delete'
        ]);
        $user = $this->Users->get($id);
        if ($this->Users->delete($user)) {
            $this->Flash->success(__('L\'utilisateur a bien été supprimé.'));
        } else {
            $this->Flash->error(__('L\'utilisateur n\'a pas pu être supprimé.'));
        }
        return $this->redirect([
            'action' => 'index'
        ]);
    }

    // called from Javascript (Ajax)
    public function getLdapLogin($userName)
    {
        $u = TableRegistry::get('LdapConnections')->getListLoginUsers();
        
        if ($u[$userName] !== null) {
            $this->set('login', $u[$userName]);
        }
        
        $this->viewBuilder()->layout = 'ajax';
    }

    // called from Javascript (Ajax)
    public function getLdapEmail($userName)
    {
        $u = TableRegistry::get('LdapConnections')->getListEmailUsers();
        
        if ($u[$userName] !== null) {
            $this->set('email', $u[$userName]);
        } else {
            $this->set('email', ' ');
        }
        
        $this->viewBuilder()->layout = 'ajax';
    }
}