package io.gmss.fiscad.controllers.user;


import io.gmss.fiscad.entities.user.Role;
import io.gmss.fiscad.entities.user.User;
import io.gmss.fiscad.enums.UserRole;
import io.gmss.fiscad.exceptions.*;
import io.gmss.fiscad.interfaces.user.UserService;
import io.gmss.fiscad.paylaods.ApiResponse;
import io.gmss.fiscad.paylaods.Login;
import io.gmss.fiscad.security.CurrentUser;
import io.gmss.fiscad.security.UserPrincipal;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;

import java.util.Set;


@RestController
@RequestMapping(value = "api/user", produces = MediaType.APPLICATION_JSON_VALUE)
//@SecurityRequirement(name = "bearer")
@Tag(name = "User")
@CrossOrigin(origins = "*")
public class UserController {

    private final UserService userService;
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);


    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/create")
    public ResponseEntity<?> createUser(@RequestBody @Valid @Validated User user) {
        try {
            user.setUsername(user.getEmail());
            user = userService.createUser(user, true);
            return new ResponseEntity<>(
                    new ApiResponse<>(true, user, "Utilisateur créé avec succès"),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @PostMapping("/change-password")
    public ResponseEntity<?> changeUserPassword(@RequestBody @Valid @Validated Login login) {
        try {
            userService.updatePassword(login.getUsername(), login.getPassword());
            return new ResponseEntity<>(
                    new ApiResponse<>(true, "Votre mot de passe à été modifiée avec succès."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @PostMapping("/reset-password")
    public ResponseEntity<?> resetUserPassword(@RequestBody @Valid @Validated Login login) {
        try {
            User user = userService.resetPassword(login.getUsername(), login.getPassword());
            return new ResponseEntity<>(
                    new ApiResponse<>(true, user, "Votre mot de passe à été réinitialisée avec succès."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @PostMapping("/validate-user-account")
    public ResponseEntity<?> validateUserAccount(@RequestBody @Valid @Validated Login login) {
        try {
            User user = userService.validateUserAccount(login.getUsername(), login.getUserRole());
            return new ResponseEntity<>(
                    new ApiResponse<>(true, user, "Cet compte à été activé avec succès."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }


    @PutMapping("/update/{id}")
    public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody User user) {
        try {
            return new ResponseEntity<>(
                    new ApiResponse<>(true, userService.updateUser(id, user), "Utilisateur modifié avec succès."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @GetMapping("/activate-or-not/{id}")
    public ResponseEntity<?> acitvateOrNotUser(@PathVariable Long id) {
        try {

            User user = userService.getUserById(id);
            if(containsRoleAnonyme(user.getRoles())){
                return new ResponseEntity<>(
                        new ApiResponse<>(false, user , "Ce compte n'est pas encore validé."),
                        HttpStatus.OK
                );
            }
            if(user.isResetPassword()){
                return new ResponseEntity<>(
                        new ApiResponse<>(false, user , "Ce compte n'est pas encore validé."),
                        HttpStatus.OK
                );
            }
            user = userService.activateOrNotUser(id);
            String message = "Utilisateur activé avec succès";
            if (!user.isActive()) {
                message = "Utilisateur désactivé avec succès";
            }
            return new ResponseEntity<>(
                    new ApiResponse<>(true, user, message),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @DeleteMapping("/delete/{id}")
    public ResponseEntity<?> deleteUser(@PathVariable Long id) {
        try {
            userService.deleteUser(id);
            return new ResponseEntity<>(
                    new ApiResponse<>(true, "User deleted successully"),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }


    @GetMapping("/all")
    public ResponseEntity<?> getAll(@CurrentUser UserPrincipal userPrincipal) {
        try {
            if(userPrincipal==null){
                return new ResponseEntity<>(
                        new ApiResponse<>(false, null, "Vous n'êtes pas authorisés à accéder à la liste des utilisateurs"),
                        HttpStatus.OK
                );
            }
            User user = userPrincipal.getUser();

            if (user.getRoles().stream().anyMatch(r -> r.getNom().equals(UserRole.ROLE_ADMIN))) {
                return new ResponseEntity<>(
                        new ApiResponse<>(true, userService.getAllUserListResponse(), "Liste des utilisateurs chargée avec succès."),
                        HttpStatus.OK
                );
            } else {
                return new ResponseEntity<>(
                        new ApiResponse<>(true, userService.getListUserResponseByStructure(userPrincipal.getUser().getStructure().getId()), "Liste des utilisateurs chargée avec succès."),
                        HttpStatus.OK
                );
            }
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @GetMapping("/all-by-structure")
    public ResponseEntity<?> getAllByStructure(@CurrentUser UserPrincipal userPrincipal) {
        try {
            if (userPrincipal.getUser().getStructure() != null) {
                return new ResponseEntity<>(
                        new ApiResponse<>(true, userService.getListUserByStructure(userPrincipal.getUser().getStructure().getId()), "Liste des utilisateurs chargée avec succès."),
                        HttpStatus.OK
                );
            } else {
                return new ResponseEntity<>(
                        new ApiResponse<>(false, "Impossible de trouver la structure indiquée."),
                        HttpStatus.OK
                );
            }
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }

    }

//    @GetMapping("/all-paged")
//    public ResponseEntity<?> getAllpaged(@RequestParam int pageNo, @RequestParam int pageSize) {
//        Pageable pageable = PageRequest.of(pageNo, pageSize);
//        return new ResponseEntity<>(
//                new ApiResponse<>(true, userService.getUserList(pageable), "Liste des utilisateurs chargée avec succès."),
//                HttpStatus.OK
//        );
//    }

    @GetMapping("/id/{id}")
    public ResponseEntity<?> getUserById(@PathVariable Long id) {
        try {
            return new ResponseEntity<>(
                    new ApiResponse<>(true, userService.getUserById(id), "User found."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @GetMapping("/username/{username}")
    public ResponseEntity<?> getUserByUsername(@PathVariable String username) {
        try {
            return new ResponseEntity<>(
                    new ApiResponse<>(true, userService.getUserByUsername(username), "User found."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @GetMapping("/all-by-role/{userrole}")
    public ResponseEntity<?> getUserByUserRole(@PathVariable UserRole userrole) {
        try {
            return new ResponseEntity<>(
                    new ApiResponse<>(true, userService.getUserByProfil(userrole), "Users found."),
                    HttpStatus.OK
            );
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
                 FileStorageException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    public boolean  containsRoleAnonyme(Set<Role> roles){
        for(Role r: roles ){
            if(r.getNom().equals(UserRole.ROLE_ANONYMOUS)){
                return true;
            }
        }
        return false;
    }
}
