package ru.soune.nocopy.service.file;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.file.CheckIncrementResult;
import ru.soune.nocopy.dto.file.CheckStatus;
import ru.soune.nocopy.entity.user.ProtectedFileCheck;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.RetryableException;
import ru.soune.nocopy.repository.ProtectedFileCheckRepository;
import ru.soune.nocopy.repository.UserRepository;

@Service
@RequiredArgsConstructor
@Slf4j
public class CheckCounterService {

    private final ProtectedFileCheckRepository protectedFileCheckRepository;

    private final UserRepository userRepository;

    @Transactional
    public void incrementCheckCount(Long userId, String mimeType) {
        try {
            ProtectedFileCheck check = protectedFileCheckRepository.findByUser_Id(userId).orElse(null);
            User user = userRepository.findById(userId).orElse(null);

            if (check == null) {
                check = initProtectCheckLimit(user,0);
            }

            boolean success = check.writeCheck(mimeType);

            if (success) {
                protectedFileCheckRepository.save(check);
                log.info("Check count incremented for user {}: count={}",
                        userId, check.getCountChecked());
                CheckIncrementResult.success(check.getCountChecked());
            }

        } catch (ObjectOptimisticLockingFailureException e) {
            log.warn("Optimistic lock failure for user {}, retrying...", userId);
            throw new RetryableException("Please try again");
        }
    }

    @Transactional(readOnly = true)
    public CheckStatus getCurrentStatus(Long userId) {
        ProtectedFileCheck check = protectedFileCheckRepository.findByUser_Id(userId)
                .orElseThrow(NullPointerException::new);

        return CheckStatus.builder()
                .userId(userId)
                .countChecked(check.getCountChecked())
                .lastCheckAt(check.getLastCheckAt())
                .build();
    }

    public ProtectedFileCheck initProtectCheckLimit(User user, Integer checked) {
        ProtectedFileCheck check = ProtectedFileCheck.builder()
                .user(user)
                .countChecked(checked)
                .build();

        return protectedFileCheckRepository.save(check);
    }

    @Transactional
    public ProtectedFileCheck updateLimit(User user, Integer limit) {
        ProtectedFileCheck check = ProtectedFileCheck.builder()
                .user(user)
                .build();

        return protectedFileCheckRepository.save(check);
    }
}
