package com.mif13.authServer.controllers;

import com.mif13.authServer.dao.UsersDao;
import com.mif13.authServer.model.User;
import com.mif13.authServer.utils.JwtHelper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.naming.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.util.MultiValueMapAdapter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UserOperations {

    private final UsersDao usersRepo;

    @Autowired
    public UserOperations(UsersDao usersRepo) {
        this.usersRepo = usersRepo;
    }

    /**
     * Procédure de login utilisée par un utilisateur
     *
     * @param login    Le login de l'utilisateur. L'utilisateur doit avoir été créé préalablement et
     *                 son login doit être présent dans le DAO.
     * @param password Le password à vérifier.
     * @return Une ResponseEntity avec le JWT dans le header "Authorization" si le login s'est bien
     * passé, et le code de statut approprié (204, 401 ou 404).
     */
    @Operation(summary = "login utilisée par un utilisateur")
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "204 No Content",
            description = "User succesfully logged in",
            content = {
                @Content()
            }
        ),
        @ApiResponse(
            responseCode = "401 Unauthorized",
            description = "Login failed",
            content = {
                @Content()
            }
        )
    })
    @PostMapping("/login")
    public ResponseEntity<Void> login(@RequestParam("login") String login,
        @RequestParam("password") String password, @RequestHeader("Origin") String origin) {

        ResponseEntity<Void> response;
        response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
        /*response.getHeaders().add("Access-Control-Expose-Headers", "Authorization");
        response.getHeaders().add("Access-Control-Allow-Origin", origin);*/

        String jwt;
        Map<String, List<String>> headers = new HashMap<>();
        MultiValueMap<String, String> headersSpring;

        Optional<User> optionalUser = usersRepo.get(login);
        if (optionalUser.isPresent()) {

            User user = optionalUser.get();

            try {
                jwt = JwtHelper.generateToken(login, origin);

                if (!jwt.isEmpty()) {
                    // on ajoute un header Authorization avec comme valeur JWT
                    headers.put("Authorization", List.of(jwt));

                } else {
                    throw new Exception("JWT is empty !");
                }
            } catch (Exception e) {
                // on ajoute un header Authorization avec comme valeur LOGIN
                headers.put("Authorization", List.of(login));
            }

            try {
                // Authentification de l'utilisateur
                user.authenticate(password);

                // Creation de la reponse HTTP
                headersSpring = new MultiValueMapAdapter<>(headers);
                response = new ResponseEntity<>(headersSpring, HttpStatus.NO_CONTENT);

            } catch (AuthenticationException e) {
                e.printStackTrace();
                response = new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
            }
        } else {
            // on ajoute un header Authentication avec comme valeur LOGIN
            headers.put("Authorization", List.of(login));
            headersSpring = new MultiValueMapAdapter<>(headers);
            response = new ResponseEntity<>(headersSpring, HttpStatus.NOT_FOUND);
        }

        return response;
    }

    @Operation(summary = "Réalise la déconnexion.")
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "204 No Content",
            description = "User succesfully logged out",
            content = {
                @Content()
            }
        ),
        @ApiResponse(
            responseCode = "401 Unauthorized",
            description = "",
            content = {
                @Content()
            }
        )
    })
    @PostMapping("/logout")
    public ResponseEntity<Void> logout(@RequestParam("login") String login) {

        ResponseEntity<Void> response;

        Optional<User> optionalUser = usersRepo.get(login);
        try {
            if (optionalUser.isPresent()) {
                User user = optionalUser.get();

                if (user.isConnected()) {
                    user.disconnect();
                    response = new ResponseEntity<>(HttpStatus.NO_CONTENT);
                } else {
                    throw new Exception("User is not connected !");
                }
            } else {
                throw new Exception("User does not exist !");
            }
        } catch (Exception e) {
            e.printStackTrace();
            response = new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }
        return response;
    }

    /**
     * .
     *
     * @param jwt    Le token JWT qui se trouve dans le header "Authorization" de la requête
     * @param origin L'origine de la requête (pour la comparer avec celle du client, stockée dans le
     *               token JWT)
     * @return Une réponse vide avec un code de statut approprié (204, 400, 401).
     */
    @Operation(summary = "Méthode destinée au serveur Node pour valider l'authentification d'un utilisateur.")
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "204 No Content",
            description = "",
            content = {
                @Content()
            }
        )
    })
    @GetMapping("/authenticate")
    public ResponseEntity<Void> authenticate(@RequestParam("jwt") String jwt,
        @RequestParam("origin") String origin) {
        ResponseEntity<Void> response = new ResponseEntity<>(HttpStatus.NO_CONTENT);

        return response;
    }
}