package com.alterdekim.hearthhack.service;

import com.alterdekim.hearthhack.dto.BoosterDTO;
import com.alterdekim.hearthhack.dto.UserDTO;
import com.alterdekim.hearthhack.entity.Booster;
import com.alterdekim.hearthhack.entity.CardBack;
import com.alterdekim.hearthhack.entity.Role;
import com.alterdekim.hearthhack.entity.User;
import com.alterdekim.hearthhack.repository.*;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.units.qual.C;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserService implements IService {

    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final PasswordEncoder passwordEncoder;
    private final HeroXPRepository heroXPRepository;
    private final DeckRepository deckRepository;
    private final CardBackRepository cardBackRepository;
    private final BoosterRepository boosterRepository;


    public void saveUser(UserDTO userDto) {
        User user = new User();
        user.setUsername(userDto.getUsername());
        user.setDisplayName(userDto.getUsername());
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        Role role = roleRepository.findByName("ROLE_USER");
        if(role == null){
            role = checkRoleExist();
        }
        user.setRoles(Collections.singletonList(role));
        userRepository.save(user);
        CardBack back = new CardBack(0, user.getId());
        cardBackRepository.save(back);
        userRepository.updateCardBackOfUser(user.getId(), back.getId());
    }


    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    public List<CardBack> getCardBacksForUserId(Long userId) {
        return cardBackRepository.findByUserId(userId);
    }

    public void setDefaultUserCardBack(Long userId, Integer cardBack) {
        CardBack cb = cardBackRepository.findByUserIdAndBackId(userId, cardBack).get();
        userRepository.updateCardBackOfUser(userId, cb.getId());
    }

    public boolean isUserHasCardBack(Long userId, Integer cardBack) {
        return cardBackRepository.isUserHasCardBack(userId, cardBack);
    }

    public void addBooster(Long userId, Integer boosterType) {
        boosterRepository.save(new Booster(userId, boosterType));
    }


    public Integer getGoldForUserId(Long userId) {
        return userRepository.findById(userId).get().getGoldBalance();
    }

    public void setGoldForUserId(Long userId, Integer gold) {
        userRepository.updateGoldOfUser(userId, gold);
    }

    public Integer getDustForUserId(Long userId) {
        return userRepository.findById(userId).get().getDustBalance();
    }

    public Integer getDefaultCardBackForUserId(Long userId) {
        return cardBackRepository.findById(
                userRepository.findById(userId).get().getDefaultCardBack()
        ).get().getBackId();
    }

    public List<BoosterDTO> getBoostersByUserId(Long userId) {
        return boosterRepository.findBoostersByUserId(userId);
    }

    public List<UserDTO> findAllUsers() {
        List<User> users = userRepository.findAll();
        return users.stream().map(this::convertEntityToDto)
                .collect(Collectors.toList());
    }

    public boolean authMe(String token) {
        String[] arr = token.split("\\-");
        if( arr.length != 3 ) return false;
        String hash = arr[1];
        long id = 0L;
        try {
            id = Long.parseLong(arr[2]);
        } catch (Exception e) {
            return false;
        }
        Optional<User> user = this.userRepository.findById(id);
        if( user.isEmpty() ) return false;
        String raw = user.get().getId() + user.get().getPassword() + user.get().getUsername();
        return passwordEncoder.matches(raw, hash);
    }

    public Long extractId(String token) {
        String[] arr = token.split("\\-");
        if(arr.length != 3) return 0L;
        return Long.parseLong(arr[2]);
    }

    public String genHash(Long id) throws Exception {
        Optional<User> user = this.userRepository.findById(id);
        if( user.isEmpty() ) throw new Exception();
        String hash = passwordEncoder.encode(user.get().getId() + user.get().getPassword() + user.get().getUsername());
        return "HH-"+hash+"-"+id;
    }


    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    private UserDTO convertEntityToDto(User user){
        UserDTO userDto = new UserDTO();
        userDto.setUsername(user.getUsername());
        return userDto;
    }

    private Role checkRoleExist() {
        Role role = new Role();
        role.setName("ROLE_USER");
        return roleRepository.save(role);
    }
}

