package ru.soune.nocopy.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.cost.CostRequest;
import ru.soune.nocopy.dto.cost.CostResponse;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.cost.CostService;

import java.util.Optional;

@Slf4j
@Component
@RequiredArgsConstructor
public class CostHandler implements RequestHandler {

    private final CostService costService;

    private final AuthTokenRepository authTokenRepository;

    private final ObjectMapper objectMapper;

    private final Integer MAX_FILES_FOR_CHECK = 1000;

    @Override
    public BaseResponse handle(BaseRequest request) throws Exception {
        CostRequest costRequest = objectMapper.convertValue(request.getMessageBody(), CostRequest.class);
        String action = costRequest.getAction();

        return switch (action) {
            case "costFileProtect" -> handleFileProtectCost(costRequest, request);
            case "checkTokensForProtect" -> handleCheckTokensForFilesProtect(costRequest, request);
            default -> new BaseResponse(
                    request.getMsgId(),
                    MessageCode.INVALID_ACTION.getCode(),
                    "Invalid action: " + action,
                    null);
        };
    }

    private BaseResponse handleFileProtectCost(CostRequest costRequest, BaseRequest request) {
        int cost = costService.protectFileCost(costRequest.getFileType());

        if (cost == 0) {
            return new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getCode(),
                    MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getDescription(),
                    CostResponse.builder()
                            .cost(cost)
                            .build());
        }

        return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
                MessageCode.SUCCESS.getDescription(),
                CostResponse.builder()
                        .cost(cost)
                        .build());
    }

    private BaseResponse handleCheckTokensForFilesProtect(CostRequest costRequest, BaseRequest request) {
        String authToken = costRequest.getAuthToken();
        Optional<AuthToken> token = authTokenRepository.findByToken(authToken);

        if (token.isEmpty()) {
           return new BaseResponse(
                    request.getMsgId(),
                    MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
                    MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
                    null);
        }

        User user = token.get().getUser();
        Integer tokens = user.getActiveTariffInfo().getTokens();

        int cost = costService.protectFileCost(costRequest.getFileType());
        int count = costRequest.getCountFilesForProtect();

        if (cost == 0 || count <= 0 || count > MAX_FILES_FOR_CHECK) {
            return new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getCode(),
                    MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getDescription(),
                    CostResponse.builder()
                            .cost(cost)
                            .countFile(count)
                            .maxFilesForCheck(MAX_FILES_FOR_CHECK)
                            .build());
        }

        int totalCost = count * cost;
        boolean success = totalCost <= tokens;
        int needToken = success ? 0: tokens - totalCost;

        CostResponse costResponse = CostResponse.builder()
                .cost(totalCost)
                .success(totalCost <= tokens)
                .needTokensCount(Math.abs(needToken))
                .build();

        return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
                MessageCode.SUCCESS.getDescription(), costResponse);
    }
}
