/*
 * Copyright (C) 2023 claas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package at.nieslony.arachne.ldap;

import at.nieslony.arachne.roles.RolesCollector;
import at.nieslony.arachne.settings.Settings;
import at.nieslony.arachne.users.ExternalUserSource;
import at.nieslony.arachne.users.UserModel;
import at.nieslony.arachne.users.UserRepository;
import at.nieslony.arachne.users.UserSettings;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *
 * @author claas
 */
@Component
@Slf4j
public class LdapUserSource implements ExternalUserSource {

    @Autowired
    private Settings settings;

    @Autowired
    UserRepository userRepository;

    @Autowired
    private RolesCollector rolesCollector;

    @Autowired
    private LdapController ldapController;

    static public String getName() {
        return "Ldap";
    }

    @Override
    public UserModel findUser(String username) {
        UserSettings userSettings = settings.getSettings(UserSettings.class);
        int ldapCacheMaxMins = userSettings.getExpirationTimeout();

        UserModel user = userRepository.findByUsernameAndExternalProvider(
                username,
                getName()
        );
        if (user == null) {
            log.info("User %s not found in database, getting from LDAP"
                    .formatted(username)
            );
            user = ldapController.getUser(username);
            if (user == null) {
                log.info("User %s neither found in database nor in LDAP"
                        .formatted(username)
                );
                return null;
            }
            Set<String> roles = rolesCollector.findRolesForUser(user);
            user.setRoles(roles);
            user.setExternalProvider(getName());
            user.createRandomPassword();
            userRepository.save(user);
        } else if (user.isExpired(ldapCacheMaxMins)) {
            log.info("User is expired. Updating from LDAP");

            UserModel ldapUser = ldapController.getUser(username);
            if (ldapUser != null) {
                user.update(ldapUser);
                Set<String> roles = rolesCollector.findRolesForUser(user);
                user.setRoles(roles);
                user.setExternalProvider(getName());
                user.createRandomPassword();
                userRepository.save(user);
            } else {
                log.info(
                        "User %s does no longer exist in LDAP. Removing user"
                                .formatted(username)
                );
                userRepository.delete(user);
            }
        }

        return user;
    }

    @Override
    public List<UserModel> findMatchingUsers(String userPattern) {
        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
    }
}
