package com.sn.sowsysrestapi.api.controller;

import com.sn.sowsysrestapi.api.converter.ReportDirectoryConverter;
import com.sn.sowsysrestapi.api.converter.UserConverter;
import com.sn.sowsysrestapi.api.dto.ReportDirectoryDTO;
import com.sn.sowsysrestapi.api.dto.UserBasicInfoDTO;
import com.sn.sowsysrestapi.api.dto.UserDTO;
import com.sn.sowsysrestapi.api.dto.UserWithActivationCodeAndStatusDTO;
import com.sn.sowsysrestapi.api.dto.input.PasswordInputDTO;
import com.sn.sowsysrestapi.api.dto.input.UserInputUpdateDTO;
import com.sn.sowsysrestapi.api.dto.input.UserWithPasswordInputDTO;
import com.sn.sowsysrestapi.domain.entity.ReportDirectory;
import com.sn.sowsysrestapi.domain.entity.User;
import com.sn.sowsysrestapi.domain.exception.UserNotFoundException;
import com.sn.sowsysrestapi.domain.repository.ReportDirectoryRepo;
import com.sn.sowsysrestapi.domain.repository.UserRepo;
import com.sn.sowsysrestapi.domain.service.ReportDirectoryService;
import com.sn.sowsysrestapi.domain.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserRepo userRepo;

    @Autowired
    private UserService userService;

    @Autowired
    private UserConverter userConverter;

    @Autowired
    private ReportDirectoryRepo reportDirectoryRepo;

    @Autowired
    private ReportDirectoryConverter reportDirectoryConverter;

    @Autowired
    private ReportDirectoryService reportDirectoryService;

    @GetMapping
    public List<UserBasicInfoDTO> list() {

        return userConverter.toCollectionWithUserBasicInfoDTO(userRepo.findAll());

    }

    @GetMapping("/find-by-username")
    public UserBasicInfoDTO findByUsername(@RequestParam String username) {

        Optional<User> user = userRepo.findByUsernameIgnoreCase(username);

        return userConverter.toBasicInfoDto(user.orElseThrow(() -> new UserNotFoundException(
                String.format("There is no user with the username %s", username)
        )));
    }

    @GetMapping("/{userCode}")
    public UserBasicInfoDTO find(@PathVariable String userCode) {

        User user = userService.findOrFail(userCode);

        UserBasicInfoDTO userBasicInfoDTO = userConverter.toBasicInfoDto(user);

        return userBasicInfoDTO;

    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public UserDTO add(@RequestBody @Valid UserWithPasswordInputDTO userWithPasswordInputDTO) {

        User user = userConverter.toEntity(userWithPasswordInputDTO);
        user = userService.save(user);

        userService.sendEmailWithActivationCode(user.getUserCode());

        return userConverter.toDto(user);

    }

    @PostMapping("/{userCode}/resend/activation-code")
    @ResponseStatus(HttpStatus.OK)
    public void resendActivationCode(@PathVariable String userCode) {

        Optional<User> user = userRepo.findByUserCode(userCode);

        userService.sendEmailWithActivationCode(user.get().getUserCode());

    }


    @PutMapping("/activate/{userCode}/{activationCode}")
    @ResponseStatus(HttpStatus.OK)
    public void updateAccStatus(@PathVariable String userCode, @PathVariable String activationCode) throws Exception {

        userService.activateAccount(userCode, activationCode);

    }

    @PutMapping("/{userCode}")
    public UserDTO update(@PathVariable String userCode, @RequestBody @Valid UserInputUpdateDTO userInputUpdateDTO) {

        ReportDirectory reportDirectoryTemp = reportDirectoryRepo.findByOwnerCode(userCode)
                .orElseThrow(() -> new UserNotFoundException(userCode));

        ReportDirectoryDTO reportDirectoryInput = reportDirectoryConverter.toDto(reportDirectoryTemp);

        ReportDirectory reportDirectoryPresent = reportDirectoryService.findOrFailByOwnerCode(userCode);
        reportDirectoryConverter.copyToEntity(reportDirectoryInput, reportDirectoryPresent);
        reportDirectoryService.update(reportDirectoryPresent);

        User userPresent = userService.findOrFail(userCode);

        boolean isActivatedStatus = userPresent.getIsActiveted();
        boolean isAdminStatus = userPresent.getAdmin();

        userPresent.setReportDirectory(reportDirectoryPresent);
        userConverter.copyToEntity(userInputUpdateDTO, userPresent);

        userPresent.setReportDirectory(reportDirectoryPresent);
        userPresent.setIsActiveted(isActivatedStatus);
        userPresent.setAdmin(isAdminStatus);

        userPresent = userService.update(userPresent);


        return userConverter.toDto(userPresent);

    }

    @PutMapping("/{userCode}/update-password")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void changePassword(@PathVariable String userCode, @RequestBody @Valid PasswordInputDTO passwordInput) {

        userService.changePassword(userCode, passwordInput.getCurrentPassword(), passwordInput.getNewPassword());

    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable String userCode) {

        userService.delete(userCode);
    }


}
