package cz.utb.tadis.auth.controller;

import cz.utb.tadis.auth.model.*;
import cz.utb.tadis.common.http.ApiResponse;
import cz.utb.tadis.auth.http.LoginRequest;
import cz.utb.tadis.auth.http.LoginResponse;
import cz.utb.tadis.auth.http.RegistrationRequest;
import cz.utb.tadis.auth.repository.RoleRepository;
import cz.utb.tadis.auth.repository.UserRepository;
import cz.utb.tadis.security.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Optional;

@RestController
@RequestMapping("/auth")
public class AuthorizationController {

    private final String DEFAULT_ROLE;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    UserRepository userRepository;

    @Autowired
    RoleRepository roleRepository;

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    public AuthorizationController(@Value("${cz.utb.tadis.model.defaultRole}") String defaultRole) {
        DEFAULT_ROLE = defaultRole;
    }

    @PostMapping("/login")
    public ResponseEntity<? extends  ApiResponse> login(@Valid @RequestBody LoginRequest loginRequest) {

        Optional<User> optUser = userRepository.findByEmail(loginRequest.getEmail());;
        if (optUser.isPresent()){
            User user = optUser.get();
            if (passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())){
                if (!user.getActive()){
                    return new ResponseEntity(new ApiResponse(HttpStatus.UNAUTHORIZED, "Inactive User","User has not been activated yet."), HttpStatus.UNAUTHORIZED);
                }
            }
        }

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword());

        Authentication authentication;
        try {
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch(AuthenticationException e){
            return new ResponseEntity(new ApiResponse(HttpStatus.UNAUTHORIZED, "Invalid Credentials","Invalid email or password."), HttpStatus.UNAUTHORIZED);
        }

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String token = jwtUtil.generateToken(authentication);

        return new ResponseEntity(new LoginResponse(HttpStatus.OK, "User login successfull.", token), HttpStatus.OK);
    }

    @PostMapping("/register")
    public ResponseEntity<? extends ApiResponse> register(@Valid @RequestBody RegistrationRequest regReq) {

        Optional<User> user = userRepository.findByEmail(regReq.getEmail());
        if (user.isPresent()){
            return new ResponseEntity(new ApiResponse(HttpStatus.CONFLICT, "User with this email already exists."), HttpStatus.CONFLICT);
        }

        Optional<Role> defaultRole = roleRepository.findByName(DEFAULT_ROLE);

        User newUser = new User(regReq.getEmail(), passwordEncoder.encode(regReq.getPassword()), false, regReq.getFirstName(), regReq.getLastName(), regReq.getCompany(), regReq.getPosition(), defaultRole.get());
        userRepository.save(newUser);

        //todo send email notification about created user

        return new ResponseEntity(new ApiResponse(HttpStatus.OK, "User has been created."), HttpStatus.OK);
    }

    @GetMapping("/available")
    public boolean isAvailable(){
        return true;
    }
}

